⬢ DragonFlyBSD Kernel Audit
DF-4582 / rs690_div0_kmod.c
← back to finding ↓ download raw
/*
 * DF-4582 / DF-4583 kernel-context reproduction (runtime-input variant).
 *
 * The verbatim rs690_crtc_bandwidth_compute() (rs690_div0_body.h) runs in
 * the live guest kernel when the admin writes a scenario number to:
 *
 *      sysctl df4582.run=<0|1|2>
 *
 * The scenario (and thus mode->clock / sideport mclk / pm.sclk) is a pure
 * runtime value here — exactly like the real driver, where mode->clock
 * arrives from the DRM ioctl — so the compiler cannot constant-fold the
 * arithmetic (the shipped radeon.ko likewise computes a runtime div:
 * see objdump 0x5ac39-0x5ac61 in VERDICT.md).
 *
 *   vulnerable build:  sysctl df4582.run=0  -> Fatal trap 0 (divide error) panic
 *   fixed build:       sysctl df4582.run=0|1|2 -> "zero divisor avoided", survives
 */
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/systm.h>
#include <sys/sysctl.h>
#include <sys/types.h>

#define KERNEL 1

/* scenario chosen at COMPILE time for the default; overridden at RUNTIME */
#ifndef DF4582_SCENARIO
#define DF4582_SCENARIO 0
#endif

#include "rs690_div0_body.h"

static int df4582_run(int s)
{
	struct df4582_rdev rdev;
	struct df4582_crtc crtc;
	struct rs690_watermark wm;

	kprintf("DF4582-KMOD: scenario %d: entering verbatim "
	    "rs690_crtc_bandwidth_compute()\n", s);
	df4582_setup(&rdev, &crtc, s);
	kprintf("DF4582-KMOD: scenario %d: mode.clock=%d kHz sideport=%d "
	    "pm.sclk=%u igp_sideport_mclk=%u\n", s, crtc.base.mode.clock,
	    rdev.mc.igp_sideport_enabled, rdev.pm.sclk.full >> 12,
	    rdev.pm.igp_sideport_mclk.full >> 12);

	rs690_crtc_bandwidth_compute(&rdev, &crtc, &wm, 0);

	kprintf("DF4582-KMOD: scenario %d: SURVIVED fifo=%u (fixed build?)\n",
	    s, wm.lb_request_fifo_depth);
	return (0);
}

static int df4582_sysctl_run(SYSCTL_HANDLER_ARGS)
{
	int s = 0, error;

	error = sysctl_handle_int(oidp, &s, 0, req);
	if (error != 0 || req->newptr == NULL)
		return (error);
	if (s < 0 || s > 2) {
		kprintf("DF4582-KMOD: scenario must be 0, 1 or 2\n");
		return (EINVAL);
	}
	return (df4582_run(s));
}

SYSCTL_NODE(, OID_AUTO, df4582, CTLFLAG_RW, 0, "DF-4582/4583 rs690 div0 repro");
SYSCTL_PROC(_df4582, OID_AUTO, run, CTLTYPE_INT | CTLFLAG_RW,
    0, 0, df4582_sysctl_run, "I", "scenario 0=clock-wrap 1=sideport-mclk0 2=pm.sclk0");

static int df4582_modevent(module_t mod, int type, void *data)
{
	switch (type) {
	case MOD_LOAD:
		kprintf("DF4582-KMOD: loaded; write sysctl df4582.run=<0|1|2>\n");
		return (0);
	case MOD_UNLOAD:
		kprintf("DF4582-KMOD: unloaded\n");
		return (0);
	}
	return (0);
}

static moduledata_t df4582_mod = { "df4582_div0", df4582_modevent, NULL };
DECLARE_MODULE(df4582_div0, df4582_mod, SI_SUB_DRIVERS, SI_ORDER_ANY);
MODULE_VERSION(df4582_div0, 1);