โฌข DragonFlyBSD Kernel Audit
DF-1851 / harness.c
โ† back to finding โ†“ download raw
/*
 * DF-1851 source-confirmation harness (hptmv 32-bit int overflow in size sum).
 *
 * sys/dev/raid/hptmv/hptproc.c:292 (hpt_set_info, under #ifdef SUPPORT_IOCTL
 * which IS defined per global.h:59):
 *    if (piop->nInBufferSize + piop->nOutBufferSize > PAGE_SIZE) return -EINVAL;
 * Both sizes are `DWORD`/unsigned int (hptintf.h:748,750) -> 32-bit addition
 * WRAPS.  Example: nIn=4095, nOut=0xFFFFF001 -> sum=0x100000001 wraps to 1,
 * passes (1 <= PAGE_SIZE).  Then kmalloc(1) and copyin(lpInBuffer, ke, 4095)
 * -> 4079-byte heap overflow.
 *
 * The sysctl handler (hptmv.status) IS registered on this guest (device
 * hptmv is in X86_64_GENERIC), but writing requires root (SYSCAP_NOSYSCTL_WR
 * โ€” maxx gets EPERM).  So this is a root-only -> kernel bug: a valid hard
 * blocker for uid0 escalation, but the primitive is real.  The harness
 * reproduces the 32-bit wrap arithmetic in userspace.
 *
 * Build:  cc -O2 -o harness harness.c
 * Run:    ./harness
 */
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

#define PAGE_SIZE 4096

int main(void) {
    /* nInBufferSize=4095, nOutBufferSize=0xFFFFF001 โ€” chosen so the 32-bit
     * sum wraps to <= PAGE_SIZE while the individual sizes are large. */
    uint32_t nIn  = 4095;
    uint32_t nOut = 0xFFFFF001u;
    uint32_t sum32 = nIn + nOut;            /* wraps mod 2^32 โ€” hptproc.c:292 */

    printf("DF-1851: hptproc.c:292 size check (32-bit unsigned add)\n");
    printf("  nInBufferSize = 0x%08x (%u)\n", nIn, nIn);
    printf("  nOutBufferSize= 0x%08x (%u)\n", nOut, nOut);
    printf("  32-bit sum    = 0x%08x (%u)\n", sum32, sum32);
    printf("  sum > PAGE_SIZE (%d)? %s\n", PAGE_SIZE,
           sum32 > PAGE_SIZE ? "YES (rejected)" : "NO (passes โ€” check bypassed)");

    if (sum32 <= PAGE_SIZE) {
        /* What the kernel then does: */
        uint32_t kalloc_size = sum32;       /* hptproc.c:297 kmalloc(1) */
        uint32_t copyin_size = nIn;         /* hptproc.c:304 copyin(4095) */
        printf("  -> kmalloc(%u) returns a %u-byte slab\n",
               kalloc_size, kalloc_size);
        printf("  -> copyin(lpInBuffer, ke_area, %u) overflows it by %u bytes\n",
               copyin_size, copyin_size - kalloc_size);
        printf("  This is the FreeBSD-SA-09:11.hptmv class: integer-overflow in size sum.\n");
    }
    return 0;
}