⬢ DragonFlyBSD Kernel Audit
DF-5755 / cesu_witness.c
← back to finding ↓ download raw
/* DF-5755/DF-5756 — kernel-side witness module.
 *
 * Loads libiconv (MODULE_DEPEND), opens the exact converter pairs the
 * msdosfs KICONV mount opens, and runs iconv_convchr() on the adversarial
 * sequences with an 8-byte output buffer — proving, from inside the kernel,
 * what sys/libiconv/iconv_ucs.c actually accepts and emits:
 *
 *   overlong-slash : "\xC0\xAF"        UTF-8 -> UTF-16BE  expect 00 2F ('/'!)
 *   overlong-4b    : "\xF0\x8F\xBF\xBF" UTF-8 -> UTF-16BE expect DB FF DC FF
 *                    (encode_surrogate() uint32 wrap: overlong U+FFFF -> 0x4FFFF)
 *   lowsur         : "\xDC\x00"        UTF-16BE -> UTF-8  expect ED B0 80 (CESU-8!)
 *   highsur-lone   : "\xD8\x3D"        UTF-16BE -> UTF-8  expect ret=-1 (rejected)
 *   valid-slash    : "\x2F"            UTF-8 -> UTF-16BE  expect 00 2F
 *   valid-pair     : "\xD8\x3D\xDE\x48" UTF-16BE -> UTF-8 expect F0 9F 98 80
 *
 * Output in dmesg: lines prefixed "witness[".
 */
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/systm.h>
#include <sys/iconv.h>

static void
witness(const char *tag, const char *to, const char *from,
    const char *in, size_t il)
{
	void *h = NULL;
	const char *src;
	char *dst;
	char out[16];
	size_t ilen, olen;
	int ret;

	if (iconv_open(to, from, &h) != 0) {
		kprintf("witness[%s]: open %s<-%s FAILED\n", tag, to, from);
		return;
	}
	memset(out, 0xAA, sizeof(out));
	src = in;
	ilen = il;
	dst = out;
	olen = sizeof(out);
	ret = iconv_convchr(h, &src, &ilen, &dst, &olen);
	kprintf("witness[%s]: convchr ret=%d consumed=%zu oleft=%zu "
	    "out=%02x %02x %02x %02x\n",
	    tag, ret, il - ilen, olen,
	    (unsigned char)out[0], (unsigned char)out[1],
	    (unsigned char)out[2], (unsigned char)out[3]);
	iconv_close(h);
}

static int
witness_modevent(module_t m, int what, void *arg)
{
	switch (what) {
	case MOD_LOAD:
		witness("overlong-slash", "UTF-16BE", "UTF-8",
		    "\xC0\xAF", 2);
		witness("overlong-4b", "UTF-16BE", "UTF-8",
		    "\xF0\x8F\xBF\xBF", 4);
		witness("lowsur", "UTF-8", "UTF-16BE",
		    "\xDC\x00", 2);
		witness("highsur-lone", "UTF-8", "UTF-16BE",
		    "\xD8\x3D", 2);
		witness("valid-slash", "UTF-16BE", "UTF-8",
		    "\x2F", 1);
		witness("valid-pair", "UTF-8", "UTF-16BE",
		    "\xD8\x3D\xDE\x48", 4);
		return 0;
	default:
		return (EOPNOTSUPP);
	}
}

static moduledata_t witness_mod = {
	"cesu_witness",
	witness_modevent,
	NULL
};

DECLARE_MODULE(cesu_witness, witness_mod, SI_SUB_DRIVERS, SI_ORDER_ANY);
MODULE_DEPEND(cesu_witness, libiconv, 2, 2, 2);