DF-1191 / harness.c
/* * DF-1191 harness — ciss_cam_complete unchecked sense_length * (userspace replica of sys/dev/raid/ciss/ciss.c:3248-3249) * * The controller returns an ErrorInfo struct whose sense_length is a u8 * (0..255). The driver does: * bzero(&csio->sense_data, SSD_FULL_SIZE); // 32 bytes * bcopy(&ce->sense_info[0], &csio->sense_data, ce->sense_length); * with NO min() against SSD_FULL_SIZE (32). A malicious controller returning * sense_length>32 overwrites adjacent union ccb fields (cdb_io, msg_ptr) and * the neighbouring heap object. This harness reproduces the overflow with a * canary guard to make it observable without ASAN. * * Build: cc -O2 -Wall -o harness harness.c * Run: ./harness */ #include <stdio.h> #include <string.h> #include <stdlib.h> #include <stdint.h> #define SSD_FULL_SIZE 32 /* sizeof(struct scsi_sense_data) */ /* controller ErrorInfo fragment */ struct ciss_error_info_replica { uint8_t sense_length; /* u8: controller-controlled, 0..255 */ uint8_t sense_info[256]; }; /* csio->sense_data sits inside union ccb; place a canary right after it. */ struct csio_replica { uint8_t sense_data[SSD_FULL_SIZE]; uint8_t canary[64]; /* stands in for cdb_io/msg_ptr/heap neighbor */ }; static int try(uint8_t sense_length) { struct ciss_error_info_replica ce; struct csio_replica csio; memset(&ce, 0xA1, sizeof(ce)); ce.sense_length = sense_length; memset(&csio, 0x00, sizeof(csio)); memset(csio.canary, 0xCD, sizeof(csio.canary)); /* poison the neighbor */ /* --- exact replica of ciss.c:3248-3249 --- */ memset(&csio.sense_data, 0, SSD_FULL_SIZE); memcpy(&csio.sense_data, &ce.sense_info[0], ce.sense_length); /* NO clamp */ int overflow = 0; for (int i = SSD_FULL_SIZE; i < (int)sizeof(csio.canary); i++) { if (csio.canary[i - SSD_FULL_SIZE] != 0xCD) { overflow++; } } int overflow_bytes = 0; if (sense_length > SSD_FULL_SIZE) overflow_bytes = sense_length - SSD_FULL_SIZE; if (overflow_bytes > (int)sizeof(csio.canary)) overflow_bytes = sizeof(csio.canary); printf("sense_length=%3u : %s (overflow into neighbor canary: %d byte%c, " "expected up to %d past sense_data)\n", sense_length, overflow ? "OVERFLOW REPRODUCED" : "in-bounds", overflow, overflow == 1 ? ' ' : 's', overflow_bytes); return overflow ? 1 : 0; } int main(void) { printf("== DF-1191 ciss_cam_complete sense_length harness ==\n"); printf("SSD_FULL_SIZE (sizeof scsi_sense_data) = %d\n\n", SSD_FULL_SIZE); int any = 0; any |= try(32); /* boundary: exactly fits, no overflow */ any |= try(64); /* overflows by 32 */ any |= try(255); /* max u8: overflows by up to 223 */ printf("\nFixed kernel clamps to imin(sense_length, SSD_FULL_SIZE) -> 0 overflow.\n"); return any ? 0 : 1; } |