DF-4989 / tws_getlock.c
/* * DF-4989 PoC โ TWS_IOCTL_GET_LOCK result is dead-stored. * * sys/dev/raid/tws/tws_user.c:280-294: * memcpy(&lpkt, ubuf->data_buf, sizeof(struct tws_lock_packet)); [read] * ... lpkt.time_remaining_msec computed in BOTH branches ... * ... and never copied back to ubuf->data_buf โ the computed value and * the granted/denied state are lost. The SUCCESS return (335) means * the ioctl "succeeded" while returning nothing. * * Consequence: a userland management tool can never observe the remaining * lock time or whether the lock was even granted, so the advisory ioctl * serialization between management agents is unenforceable client-side. * * Requires /dev/tws0; without the controller exits ENOENT. */ #include <sys/ioctl.h> #include <stdio.h> #include <string.h> #include <errno.h> #include <fcntl.h> #include <unistd.h> struct tws_driver_packet { unsigned int control_code, status, unique_id, sequence_id, os_status, buffer_length; } __attribute__((packed)); struct tws_lock_packet { unsigned int timeout_msec; unsigned int time_remaining_msec; unsigned int force_flag; } __attribute__((packed)); struct tws_command_header { unsigned char sense_data[18]; struct { unsigned short srcnum; unsigned char reserved; unsigned char status; unsigned short error; unsigned char res__srcid; unsigned char res__severity; } __attribute__((packed)) status_block; unsigned char err_specific_desc[98]; struct { unsigned char size_header; unsigned short request_id; unsigned char size_sense; } __attribute__((packed)) header_desc; } __attribute__((packed)); struct tws_command_packet { struct tws_command_header hdr; unsigned char cmd[896]; } __attribute__((packed)); struct tws_ioctl_with_payload { struct tws_driver_packet driver_pkt; char padding[488]; struct tws_command_packet cmd_pkt; union { struct tws_lock_packet lock_pkt; char data_buf[136]; } payload; } __attribute__((packed)); #define TWS_IOCTL_GET_LOCK _IOWR('T', 207, struct tws_ioctl_with_payload) #define TWS_IOCTL_RELEASE_LOCK _IOWR('T', 208, struct tws_ioctl_with_payload) #define TWS_IOCTL_LOCK_ALREADY_HELD 0x1002 int main(void) { static struct tws_ioctl_with_payload buf, buf2; int fd, error; fd = open("/dev/tws0", O_RDWR); if (fd < 0) { printf("open(/dev/tws0): %s โ no 3ware controller (hardware-gated)\n", strerror(errno)); return (2); } /* ask for the lock for 10 minutes */ buf.payload.lock_pkt.timeout_msec = 10u * 60u * 1000u; buf.payload.lock_pkt.force_flag = 0; error = ioctl(fd, TWS_IOCTL_GET_LOCK, &buf); printf("DF4989: GET_LOCK rc=%d errno=%s driver_pkt.status=0x%x " "time_remaining_msec=0x%x (unchanged 0x0 => result never " "copied back)\n", error, strerror(errno), buf.driver_pkt.status, buf.payload.lock_pkt.time_remaining_msec); /* second request while held: driver takes the ALREADY_HELD branch and * computes the remaining time ... which is again never returned */ buf2.payload.lock_pkt.timeout_msec = 10u * 60u * 1000u; error = ioctl(fd, TWS_IOCTL_GET_LOCK, &buf2); printf("DF4989: GET_LOCK#2 rc=%d errno=%s driver_pkt.status=0x%x " "(expect 0x%x) time_remaining_msec=0x%x (still 0 => dead store)\n", error, strerror(errno), buf2.driver_pkt.status, TWS_IOCTL_LOCK_ALREADY_HELD, buf2.payload.lock_pkt.time_remaining_msec); ioctl(fd, TWS_IOCTL_RELEASE_LOCK, &buf); close(fd); return (0); } |