DF-4541 / hptinit.c
/* * hptinit.c - trigger for DF-4541 * * hptmv: HPT_IOCTL_SET_ARRAY_STATE / AS_INITIALIZE_START queues the DPC * with the wrong flag (VERIFY instead of INITIALIZE) at * sys/dev/raid/hptmv/ioctl.c:580, so rf_initializing is never set; the * ioctl thread then spins in 1-tick tsleep loops for 80 seconds * (hz*80 iterations, ioctl.c:583-589) and returns 0 (success) although * nothing was initialized. * * The hptmv ioctl channel is the writable sysctl dev.hptmv.status * (hptproc.c:614-617, CTLFLAG_RW): the packet is an HPT_IOCTL_PARAM * (hptintf.h:744-753) followed by the raw in/out buffers. * * Usage: ./hptinit <array-id> * (Requires a HighPoint RocketRAID 18xx/22xx SATA controller with a * valid RAID1/5 array id reported by HPT_IOCTL_GET_LOGICAL_DEVICES. * Root only - sysctl writes require privilege.) * * Expected on vulnerable driver, id=<valid array>, state=AS_INITIALIZE_START: * - ioctl takes ~80 seconds (80 * hz 1-tick tsleep iterations) * - returns success (sysctl write returns the written length) * - driver log shows "Verifying started." (VERIFY event), NOT * "Initializing started." -- initialization never happened. */ #include <sys/types.h> #include <sys/sysctl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #define HPT_IOCTL_MAGIC 0xA1B2C3D4 #define HPT_IOCTL_SET_ARRAY_STATE (15 + 0xFF00) #define AS_INITIALIZE_START 7 typedef unsigned int DWORD; typedef unsigned long ULONG_PTR; typedef void *LPVOID; typedef DWORD *LPDWORD; typedef struct _HPT_IOCTL_PARAM { DWORD Magic; DWORD dwIoControlCode; LPVOID lpInBuffer; DWORD nInBufferSize; LPVOID lpOutBuffer; DWORD nOutBufferSize; LPDWORD lpBytesReturned; } HPT_IOCTL_PARAM; #pragma pack(1) typedef struct { DWORD idArray; /* DEVICEID */ DWORD state; /* AS_INITIALIZE_START */ } HPT_SET_STATE_PARAM_T; #pragma pack() int main(int argc, char **argv) { HPT_IOCTL_PARAM p; HPT_SET_STATE_PARAM_T in; unsigned char packet[sizeof(p) + sizeof(in)]; char out[16]; size_t len; time_t t0, t1; if (argc != 2) { fprintf(stderr, "usage: %s <array-device-id>\n", argv[0]); return 2; } memset(&p, 0, sizeof(p)); p.Magic = HPT_IOCTL_MAGIC; p.dwIoControlCode = HPT_IOCTL_SET_ARRAY_STATE; p.lpInBuffer = ∈ p.nInBufferSize = sizeof(in); p.lpOutBuffer = out; p.nOutBufferSize = 0; p.lpBytesReturned = NULL; memset(&in, 0, sizeof(in)); in.idArray = (DWORD)strtoul(argv[1], NULL, 0); in.state = AS_INITIALIZE_START; /* the sysctl handler wants the flat packet: param struct then in buf */ memcpy(packet, &p, sizeof(p)); memcpy(packet + sizeof(p), &in, sizeof(in)); len = sizeof(packet); t0 = time(NULL); if (sysctlbyname("dev.hptmv.status", NULL, NULL, packet, len) < 0) { perror("sysctl dev.hptmv.status (write)"); return 1; } t1 = time(NULL); printf("SET_ARRAY_STATE(AS_INITIALIZE_START) returned SUCCESS in %lld s\n", (long long)(t1 - t0)); printf("BUG if: elapsed ~= 80s and dmesg says 'Verifying started.'\n"); return 0; } |