DF-2559 / rig.c
/* * DF-2559 -- SO_PASSCRED SCM_CREDS auto-creation path in uipc_send * (uipc_usrreq.c:693-698): the return of sbcreatecontrol() (M_NOWAIT) * is never checked; under mbuf exhaustion it returns NULL and * unp_internalize(NULL) dereferences mtod(NULL,...) -> kernel panic. * * Rig: sysctl kern.dfv2559 = N pins ALL mbufs except N, then a local * unprivileged sender triggers the SOCK_DGRAM + SO_PASSCRED path. */ #include <sys/param.h> #include <sys/kernel.h> #include <sys/systm.h> #include <sys/sysctl.h> #include <sys/mbuf.h> #include <sys/malloc.h> static struct mbuf **df_held; static int df_nheld; static int dfv2559_backing; static int dfv2559_sysctl(SYSCTL_HANDLER_ARGS) { int error, v = 0; int i, budget = 4000000; if (req->newptr != NULL) { v = dfv2559_backing; error = sysctl_handle_int(oidp, &v, 0, req); if (error) return error; dfv2559_backing = v; if (v < -1 || v > 64) return EINVAL; /* release previous pins */ for (i = 0; i < df_nheld; i++) m_free(df_held[i]); df_nheld = 0; if (v == -1) return 0; /* just release */ /* pin everything we can */ while (budget--) { struct mbuf *m = m_get(M_NOWAIT, MT_DATA); if (m == NULL) break; df_held[df_nheld++] = m; if (df_nheld == 3900000) break; } kprintf("dfv2559: pinned %d mbufs; now releasing %d\n", df_nheld, v); /* release v mbufs back to the free pool */ for (i = 0; i < v && df_nheld > 0; i++) m_free(df_held[--df_nheld]); return 0; } return sysctl_handle_int(oidp, &v, 0, req); } SYSCTL_PROC(_kern, OID_AUTO, dfv2559, CTLTYPE_INT | CTLFLAG_RW, 0, 0, dfv2559_sysctl, "I", "pin all mbufs minus N (-1 releases)"); static int dfv2559_load(module_t mod, int what, void *arg) { switch (what) { case MOD_LOAD: df_held = kmalloc(sizeof(*df_held) * 4000000, M_TEMP, M_WAITOK); kprintf("dfv2559: loaded\n"); return 0; case MOD_UNLOAD: kfree(df_held, M_TEMP); return 0; default: return 0; } } static moduledata_t dfv2559_mod = { "dfv2559", dfv2559_load, NULL }; DECLARE_MODULE(dfv2559, dfv2559_mod, SI_SUB_DRIVERS, SI_ORDER_ANY); |