DF-4781 / dconsnull.c
/* * dconsnull.c -- DF-4781 / DF-4782 PoC (TEST ONLY, never for sys/). * * Proves the NULL-deref sinks reached by two unchecked wiring paths in * sys/dev/misc/dcons/dcons_os.c: * * DF-4781: dcons_drv_init() (dcons_os.c:462-464) does not check * contigmalloc() for NULL before dcons_init(dg.buf, ...). * dcons_init() immediately writes buf->osize[0] (dcons.c:147) * => NULL+offset store -> Fatal trap 12 at kldload time. * * DF-4782: in a kernel built with `device dcons`, /dev/dcons is created * by dcons_cninit_fini() (dcons_os.c:385) but si_drv1 is only * wired by dcons_attach_port() (dcons_os.c:493) on the module * path. First write to the tty runs dcons_tty_start() * (dcons_os.c:320) which does * dc = tp->t_dev->si_drv1; // NULL * dcons_os_putc(dc, c); // dcons_os.c:329 * => dcons_putc(NULL, c) reads ch->buf at NULL+16 (dcons.c:118) * => Fatal trap 12. * * Modes (kenv dconsnull.mode=N before kldload): * 0 = negative control: init a real 16KB buffer, putc/checkc, print OK. * 1 = dcons_init(NULL, 16384, sc) [DF-4781 sink] * 2 = dcons_putc(NULL, 'A') [DF-4782 sink] */ #include <sys/param.h> #include <sys/kernel.h> #include <sys/module.h> #include <sys/conf.h> #include <sys/systm.h> #include <sys/malloc.h> #include <sys/kenv.h> #include "dcons.h" static struct dcons_softc dsc[DCONS_NPORT]; static char nbuf[16 * 1024] __aligned(4); static int dconsnull_modevent(module_t mod, int type, void *data) { char *v; int mode; switch (type) { case MOD_LOAD: if ((v = kgetenv("dconsnull.mode")) == NULL) mode = 0; else mode = v[0] - '0'; kprintf("dconsnull: loaded, mode=%d\n", mode); /* Negative control: the same calls with a valid buffer. */ if (mode == 0) { dcons_init((struct dcons_buf *)nbuf, sizeof(nbuf), dsc); dcons_putc(&dsc[DCONS_CON], 'A'); kprintf("dconsnull: NEGCTRL init+putc OK, checkc=%c\n", dcons_checkc(&dsc[DCONS_CON])); break; } if (mode == 1) { kprintf("dconsnull: DF-4781: calling dcons_init(NULL, " "16384, sc) -- unchecked contigmalloc sink\n"); dcons_init(NULL, 16 * 1024, dsc); kprintf("dconsnull: NOT REACHED\n"); break; } if (mode == 2) { kprintf("dconsnull: DF-4782: calling dcons_putc(NULL, " "'A') -- static-console si_drv1==NULL sink\n"); dcons_putc(NULL, 'A'); kprintf("dconsnull: NOT REACHED\n"); break; } break; default: break; } return (0); } DEV_MODULE(dconsnull, dconsnull_modevent, NULL); MODULE_DEPEND(dconsnull, dcons, DCONS_VERSION, DCONS_VERSION, DCONS_VERSION); |