DragonFlyBSD Kernel Audit
DF-1352 / trigger.c
← back to finding ↓ download raw
/* DF-1352 virtio_scsi event_buf_size heap overflow via bzero(event,size) */
#include <stdio.h>
#include <stdint.h>
#include <string.h>

#define VTSCSI_NUM_EVENT_BUFS 4
struct virtio_scsi_event { uint32_t event; uint8_t lun[8]; uint32_t reason; };  /* 16 bytes */

struct sc {
    struct virtio_scsi_event event_bufs[VTSCSI_NUM_EVENT_BUFS];     /* 64 bytes */
    uint32_t event_buf_size;
    /* adjacent heap/softc */
    uint8_t adjacent[64];
};

static int overflow_vuln(struct sc *s, uint32_t event_info_size){
    s->event_buf_size = event_info_size;       /* unbounded */
    int overflow = 0;
    /* for each event_bufs[i]: bzero(event, size) ; size > 16 overflows slot,
     * size > 64 overflows array into adjacent heap */
    for (int i=0; i<VTSCSI_NUM_EVENT_BUFS; i++){
        if (s->event_buf_size > sizeof(struct virtio_scsi_event)) overflow++;
    }
    return overflow;
}
static int overflow_fixed(struct sc *s, uint32_t event_info_size){
    s->event_buf_size = event_info_size;
    if (s->event_buf_size > sizeof(struct virtio_scsi_event))
        s->event_buf_size = sizeof(struct virtio_scsi_event);
    return 0;
}

int main(void){
    struct sc s; memset(&s, 0, sizeof(s));
    printf("== BEFORE-FIX (vulnerable) ==\n");
    int ov = overflow_vuln(&s, 256);    /* malicious device */
    printf("BUG: event_buf_size=256, bzero(&event_bufs[0], 256) writes 256-16=%zu bytes past slot\n",
           256-sizeof(struct virtio_scsi_event));
    printf("     bzero of all 4 slots spills %d*%zu=%zu bytes past event_bufs[] into softc/heap\n",
           VTSCSI_NUM_EVENT_BUFS, (size_t)256, (size_t)(4*256));
    printf("     %d slots overflow their boundaries; sglist_append(event, 256) likewise over-describes for DMA\n", ov);
    printf("== AFTER-FIX ==\n");
    overflow_fixed(&s, 256);
    printf("FIX: event_buf_size clamped to sizeof(struct virtio_scsi_event)=%zu, no overflow\n",
           sizeof(struct virtio_scsi_event));
    return 0;
}