DF-2233 / race2233_harness.c
/* * DF-2233 -- walk hammer harness (compiled into the same KLD as the * PRISTINE libiconv sources; see Makefile). * * sys/libiconv/iconv.c walks the iconv_cslist / iconv_converters TAILQs * WITHOUT holding iconv_lock in: * iconv_lookupconv() (iconv.c:145-160) * iconv_lookupcs() (iconv.c:162-176) * iconv_open() (iconv.c:232-266) * while the free paths (iconv_unregister_cspair via the sysctl-add `bad:` * path, iconv_unregister_converter / iconv_mod_unload via kldunload) * free the walked nodes under LK_EXCLUSIVE. * * This harness replicates exactly what a LIBICONV filesystem mount does * (msdosfs_vfsops.c:119-130 / cd9660 call the same iconv_open through the * VFS_DECLARE_ICONV bridge), but in a tight in-kernel loop so the race * window is exercised millions of times per second: * * - failing lookup "ZZQ9"->"ZZQ9": walks the FULL cslist and then the * FULL converter list (composite construction loop); * - every 32nd iteration a successful "UTF-16BE"->"UTF-8" open+close: * exercises the ICONV_CONVERTER_OPEN(csp->cp_dcp) dispatch on a live * pair (kobj method call). */ #include <sys/param.h> #include <sys/kernel.h> #include <sys/systm.h> #include <sys/sysctl.h> #include <sys/iconv.h> static long rh_walks; /* failed lookups: full lockless walk of both lists */ static long rh_opens; /* successful direct opens (dispatch via cp_dcp) */ static long rh_iters; static int rh_doopens; /* sysctl-tunable: add successful opens (holds refs) */ static int rh_run(SYSCTL_HANDLER_ARGS) { int iters = 0; int error, i; void *h; error = sysctl_handle_int(oidp, &iters, 0, req); if (error != 0 || req->newptr == NULL) return (error); for (i = 0; i < iters; i++) { error = iconv_open("ZZQ9", "ZZQ9", &h); if (error == 0) { iconv_close(h); } else { atomic_add_long(&rh_walks, 1); } if (rh_doopens && (i & 0x1f) == 0) { error = iconv_open("UTF-16BE", "UTF-8", &h); if (error == 0) { iconv_close(h); atomic_add_long(&rh_opens, 1); } } atomic_add_long(&rh_iters, 1); } return (0); } /* CTLFLAG_NOLOCK: several hammer processes must run the handler concurrently */ SYSCTL_PROC(_debug, OID_AUTO, race2233_run, CTLFLAG_RW | CTLTYPE_INT | CTLFLAG_NOLOCK, 0, 0, rh_run, "I", "hammer iconv_open lockless walks"); SYSCTL_LONG(_debug, OID_AUTO, race2233_walks, CTLFLAG_RD, &rh_walks, 0, "failed lookups (full walks)"); SYSCTL_LONG(_debug, OID_AUTO, race2233_opens, CTLFLAG_RD, &rh_opens, 0, "successful direct opens"); SYSCTL_LONG(_debug, OID_AUTO, race2233_iters, CTLFLAG_RD, &rh_iters, 0, "iterations completed"); SYSCTL_INT(_debug, OID_AUTO, race2233_doopens, CTLFLAG_RW, &rh_doopens, 0, "also perform successful opens (holds converter refs)"); |