⬢ DragonFlyBSD Kernel Audit
DF-1215 / bktrig_nodep.c
← back to finding ↓ download raw
/*
 * bktrig.c -- DF-1215 verification rig (DragonFly KLD module)
 *
 * The audit QEMU guest has no Brooktree bt848/878 PCI capture card, so the
 * production bktr driver never attaches and /dev/bktr0 is never created.
 * This rig makes the PRODUCTION ioctl handler reachable anyway:
 *
 *   - /dev/bktrig0 (mode 0666) with its own tiny dev_ops
 *   - d_ioctl dispatches DIRECTLY to the production video_ioctl()
 *     (sys/dev/video/bktr/bktr_core.c:1202) resolved from the loaded
 *     production bktr.ko module (unmodified code, unfixed on the baseline
 *     kernel, fixed after the fix-build)
 *   - the softc passed to video_ioctl is a synthetic, zeroed struct
 *     bktr_softc with bigbuf != 0, mirroring the post-attach state on real
 *     hardware (attach allocates bigbuf before any open can occur, so the
 *     bigbuf gate in bktr_ioctl (bktr_os.c) passes on real hardware too)
 *
 * Only METEORSVIDEO / METEORGVIDEO are exercised by the PoC: both cases
 * touch softc fields only (no MMIO), so no real bt848 registers are needed
 * to demonstrate the missing privilege check on the production path.
 *
 * On real hardware the same production path is reached by ANY user because
 * the bktr device nodes are created mode 0444 (bktr_os.c:325).
 */
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/conf.h>
#include <sys/device.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/malloc.h>
#include <sys/proc.h>
#include <sys/event.h>
#include <sys/signalvar.h>
#include <sys/bus.h>
#include <sys/rman.h>
#include <sys/thread.h>

#include <dev/video/meteor/ioctl_meteor.h>
#include <dev/video/bktr/ioctl_bt848.h>
#include <dev/video/bktr/bktr_reg.h>

/* production entry point: bktr_core.c:1202 (global, resolved from bktr.ko
 * or the fix-built kernel) */
extern int video_ioctl(bktr_ptr_t bktr, int unit, ioctl_cmd_t cmd,
		       caddr_t arg, struct thread *td);

static cdev_t	bktrig_dev;
static bktr_ptr_t rig_sc;

static int
bktrig_open(struct dev_open_args *ap)
{
	return 0;
}

static int
bktrig_close(struct dev_close_args *ap)
{
	return 0;
}

static int
bktrig_ioctl(struct dev_ioctl_args *ap)
{
	/* dispatch to the PRODUCTION handler on the synthetic softc */
	return video_ioctl(rig_sc, 0, ap->a_cmd, ap->a_data, curthread);
}

static struct dev_ops bktrig_ops = {
	{ "bktrig", 0, 0 },
	.d_open =	bktrig_open,
	.d_close =	bktrig_close,
	.d_ioctl =	bktrig_ioctl,
};

static int
bktrig_modevent(module_t mod, int type, void *data)
{
	switch (type) {
	case MOD_LOAD:
		rig_sc = kmalloc(sizeof(struct bktr_softc), M_DEVBUF,
				 M_WAITOK | M_ZERO);
		if (rig_sc == NULL)
			return (ENOMEM);
		/* post-attach state on real hardware: bigbuf allocated */
		rig_sc->bigbuf = (vm_offset_t)0xDEADB000;
		rig_sc->flags = METEOR_INITALIZED;
		bktrig_dev = make_dev(&bktrig_ops, 0, UID_ROOT, GID_WHEEL,
				      0666, "bktrig0");
		kprintf("bktrig: DF-1215 rig ready /dev/bktrig0 sc=%p "
			"(video_ioctl=%p)\n", rig_sc, video_ioctl);
		return 0;
	case MOD_UNLOAD:
		destroy_dev(bktrig_dev);
		kfree(rig_sc, M_DEVBUF);
		rig_sc = NULL;
		return 0;
	default:
		return 0;
	}
}

static moduledata_t bktrig_mod = {
	"bktrig",
	bktrig_modevent,
	NULL
};

/* pull in the production (unmodified) bktr.ko for video_ioctl.
 * NB: on the FIX-built kernel (bktr compiled in) use the BKTRIG_NODEP
 * variant so the auto-load of bktr.ko ("module already exists") does not
 * fail -- video_ioctl then resolves from the kernel's own globals. */
#ifndef BKTRIG_NODEP
/* nodep variant: no MODULE_DEPEND (fix kernel has bktr built in) */
#endif
DECLARE_MODULE(bktrig, bktrig_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);