DF-1234 / asr_fillmsg_leak.c
/* * DF-1234 — ASR_queue_i (I2OUSRCMD) heap info-leak via u_int16_t truncation * * Bug (sys/dev/raid/asr/asr.c): * Line 486: ASR_fillMessage(void *Message, u_int16_t size) * -> bzero(Message_Ptr, size) only bzeros the low 16 bits of size. * Line 3262: ReplySizeInBytes = (I2O_MESSAGE_FRAME_getMessageSize(...) << 2) * -> from user-controlled reply MessageSize field, up to 0xFFFF<<2 = ~256KB. * Line 3273: kmalloc(ReplySizeInBytes, M_TEMP, M_WAITOK) -- NO M_ZERO. * Line 3282: ASR_fillMessage(Reply_Ptr, ReplySizeInBytes) * -> silently truncated to u_int16_t. * Line 3575: copyout(Reply_Ptr, Reply, ReplySizeInBytes) * -> ships up to 256KB of UNINITIALIZED slab to userspace. * * Example: a reply MessageSize of 0x4000 yields ReplySizeInBytes = 0x10000. * ASR_fillMessage's u_int16_t size param becomes 0 -> bzero does nothing. * Only ~30-60 bytes get touched by the header writes (setVersionOffset, * setMessageSize etc.). The remaining ~64KB of stale slab is copyout'd. * * Privilege: asr_open() at asr.c:3107 enforces SYSCAP_RESTRICTEDROOT -- only * root or a process granted the restricted-root capability can reach * I2OUSRCMD. So this is root->kernel info-leak (slab-grooming / KASLR-defeat * primitive) -- not unprivileged. * * THIS GUEST: no DPT SmartRAID controller in pciconf -l; /dev/asrN absent; * ioctl not reachable. PoC prints reachability. On a host with an asr(4) * controller, sending I2OUSRCMD with a crafted reply frame leaks up to 256KB * of kernel slab. */ #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <sys/ioctl.h> #ifndef I2OUSRCMD #define I2OUSRCMD _IOWR('A', 1, u_int8_t) /* asr.c:3788 */ #endif int main(void) { int fd, i; const char *devs[] = {"/dev/asr0", "/dev/asr1", "/dev/asr2", "/dev/asr3"}; printf("[DF-1234] asr ASR_queue_i heap info-leak demonstrator\n"); printf("[DF-1234] Bug: ASR_fillMessage takes u_int16_t size (asr.c:486);\n"); printf("[DF-1234] ReplySizeInBytes can be up to 0x3FFFC (~256KB).\n"); printf("[DF-1234] bzero truncates to 16 bits; kmalloc has no M_ZERO;\n"); printf("[DF-1234] copyout at :3575 ships uninitialized slab.\n\n"); fd = -1; for (i = 0; i < 4; i++) { fd = open(devs[i], O_RDWR); if (fd >= 0) { printf("[DF-1234] Opened %s -- controller present.\n", devs[i]); printf("[DF-1234] (Triggering the actual leak requires SYSCAP_RESTRICTEDROOT,\n"); printf("[DF-1234] crafting a 0x4000-sized reply frame, and a controller.\n"); printf("[DF-1234] See VERDICT.md for the precise chain.)\n"); close(fd); return (0); } } printf("[DF-1234] No /dev/asrN found: %s\n", strerror(errno)); printf("[DF-1234] No DPT SmartRAID on guest -> ioctl not reachable.\n"); printf("[DF-1234] Source-level verification only (see VERDICT.md).\n"); return (0); } |