DF-1352 / trigger.c
/* 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; } |