⬢ DragonFlyBSD Kernel Audit
DF-5447 / uvscom_preparam_harness.c
← back to finding ↓ download raw
/*
 * DF-5447 KLD harness -- PRODUCTION-CODE demonstration that
 * uvscom_pre_param() rejects every baud rate, including all eleven
 * supported ones (uvscom.c:514-533).
 *
 * Method: this module #includes the unmodified production
 * sys/bus/u4b/serial/uvscom.c into its own translation unit (with the
 * newbus DRIVER_MODULE / MODULE_DEPEND / MODULE_VERSION registration
 * macros expanded to nothing so the harness does not register a second
 * "uvscom" driver on uhub), then calls the real, static
 * uvscom_pre_param() for every speed the hardware supports.
 *
 * Production contract (usb_serial.c:1678-1684):
 *
 *   if (sc->sc_callback->ucom_pre_param) {
 *           error = (sc->sc_callback->ucom_pre_param) (sc, t);
 *           if (error) {
 *                   goto done;          <-- termios change REJECTED
 *           }
 *   }
 *
 * so any non-zero return kills the tcsetattr (and silently kills the
 * open-time programming at usb_serial.c:842, whose error is discarded).
 *
 * Expected baseline (phase A): all 11 supported speeds -> EINVAL (35),
 * i.e. "SUPPORTED speeds accepted: 0/11".
 * Expected after fix.diff (phase B, rerun of the same harness against the
 * patched /usr/src copy): 11/11 accepted, B230400 -> EINVAL.
 */
#include <sys/param.h>
#include <sys/types.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/bus.h>
#include <sys/lock.h>

/* NOTE: no u4b/usb* headers here on purpose: uvscom.c must include them
 * itself (its own include order -- USB_DEBUG_VAR before usb_debug.h --
 * is required for DPRINTF/DPRINTFN to be defined). */

MODULE_DEPEND(hx5447, usb, 1, 1, 1);
MODULE_DEPEND(hx5447, ucom, 1, 1, 1);

/*
 * Neuter the newbus/module registration the production file would
 * otherwise perform. DRIVER_MODULE lives in <sys/bus.h> (already
 * included above), MODULE_DEPEND/MODULE_VERSION in <sys/module.h>.
 */
#undef DRIVER_MODULE
#undef DRIVER_MODULE_ORDERED
#undef MODULE_DEPEND
#undef MODULE_VERSION
#define DRIVER_MODULE(name, busname, driver, devclass, evh, arg)
#define DRIVER_MODULE_ORDERED(name, busname, driver, devclass, evh, arg, order)
#define MODULE_DEPEND(module, mdepend, vmin, vpref, vmax)
#define MODULE_VERSION(module, version)

/* THE PRODUCTION DRIVER, textually unmodified. */
#include "../uvscom.c"

/*
 * Keep -Werror happy: uvscom_devclass and uvscom_driver are normally
 * referenced by DRIVER_MODULE, which we expanded away.
 */
static void
hx5447_touch_statics(void)
{

	if (uvscom_devclass != NULL)
		kprintf("UVS5447: unexpected devclass %p\n", uvscom_devclass);
	kprintf("UVS5447: production driver \"%s\" compiled into harness "
	    "(registration neutered)\n", uvscom_driver.name);
}

static const speed_t hx_speeds[] = {
	B150, B300, B600, B1200, B2400, B4800,
	B9600, B19200, B38400, B57600, B115200,
};

static int
hx5447_run(char phase)
{
	struct ucom_softc ucom_stub;
	struct termios t;
	int accepted = 0;
	size_t i;
	int e;

	memset(&ucom_stub, 0, sizeof(ucom_stub));
	memset(&t, 0, sizeof(t));

	kprintf("UVS5447[%c]: calling production uvscom_pre_param() "
	    "(uvscom.c:514-533) for all 11 supported speeds\n", phase);

	for (i = 0; i < sizeof(hx_speeds) / sizeof(hx_speeds[0]); i++) {
		t.c_ospeed = hx_speeds[i];
		e = uvscom_pre_param(&ucom_stub, &t);
		kprintf("UVS5447[%c]: pre_param(B%d) = %d (%s)\n",
		    phase, (int)hx_speeds[i], e,
		    e == 0 ? "ACCEPTED" :
		    e == EINVAL ? "EINVAL -- REJECTED" : "unexpected");
		if (e == 0)
			accepted++;
	}

	/* B230400 is NOT supported by the hardware (no case label). */
	t.c_ospeed = B230400;
	e = uvscom_pre_param(&ucom_stub, &t);
	kprintf("UVS5447[%c]: pre_param(B230400) = %d (%s, expected EINVAL)\n",
	    phase, e, e == EINVAL ? "ok" : "WRONG");

	kprintf("UVS5447[%c]: SUPPORTED speeds accepted: %d/11 %s\n",
	    phase, accepted, accepted == 11 ? "(fixed)" :
	    accepted == 0 ? "(BUG: every tcsetattr fails EINVAL, "
	    "uvscom_cfg_param() is unreachable, uvscom.c:532 return(0) dead)"
	    : "(partial?)");

	return (accepted == 11 ? 0 : 1);
}

static int
hx5447_modevent(module_t mod, int type, void *data)
{
	int error = 0;

	switch (type) {
	case MOD_LOAD:
		hx5447_touch_statics();
		kprintf("UVS5447: DF-5447 production-code harness: "
		    "uvscom_pre_param inverted switch\n");
		hx5447_run('A');
		kprintf("UVS5447: harness complete\n");
		break;
	case MOD_UNLOAD:
		break;
	default:
		error = EOPNOTSUPP;
		break;
	}
	return (error);
}

static moduledata_t hx_mod = { "uvscompreparam", hx5447_modevent, 0 };
DECLARE_MODULE(uvscompreparam, hx_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);