DF-5779 / seqputs_rigc.c
/* * DF-5779 rig C — the %s variant. Same seq_puts() shim contract, but the * dynamic data string contains %s: the kernel printf core pulls a pointer * out of a vararg slot that was never set (subr_prf.c:751) and runs * strlen()/copy on it -> wild kernel read. Expected: panic or garbage * memory leak into m->buf. Load LAST; expect to reset the guest after. */ #include <sys/param.h> #include <sys/kernel.h> #include <sys/systm.h> #include <sys/module.h> struct seq_file { char *buf; size_t size; }; #define seq_puts(m, str) ksnprintf((m)->buf, (m)->size, str) static void rig_run(void) { struct seq_file m; char backing[256]; /* 9 conversions: burns rcx/r8/r9 register-save slots, then walks the * stack overflow area (return address, saved regs, locals) of the * ksnprintf frame -> strlen()/copy on wild kernel pointers. */ const char *data = "m=%s s=%s x=%s y=%s z=%s w=%s v=%s u=%s t=%s\n"; m.buf = backing; m.size = sizeof(backing); kprintf("seqputs_rigc: firing %%s-walk on unset varargs...\n"); seq_puts(&m, data); kprintf("seqputs_rigc: survived; buf='%s'\n", backing); } static int seqputs_rigc_load(struct module *m __unused, int what, void *arg __unused) { switch (what) { case MOD_LOAD: rig_run(); return (0); default: return (0); } } static moduledata_t seqputs_rigc_mod = { "seqputs_rigc", seqputs_rigc_load, NULL }; DECLARE_MODULE(seqputs_rigc, seqputs_rigc_mod, SI_SUB_DRIVERS, SI_ORDER_ANY); MODULE_VERSION(seqputs_rigc, 1); |