⬢ DragonFlyBSD Kernel Audit
DF-2226 / prop_empty_key.c
← back to finding ↓ download raw
/* DF-2226: prop_dictionary internalizer accepts an empty <key></key>,
 * violating the keysym non-empty invariant that _prop_dict_keysym_externalize
 * asserts (_PROP_ASSERT(pdk->pdk_key[0] != '\0'), prop_dictionary.c:248).
 * DFly libprop internalize wants a <plist> wrapper; same code is compiled
 * into the kernel (sys/libprop is shared with lib/libprop). */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <libprop/proplib.h>

static const char *GOOD_KEY_XML =
    "<plist version=\"1.0\"><dict><key>ok</key><string>x</string></dict></plist>";
static const char *EMPTY_KEY_XML =
    "<plist version=\"1.0\"><dict><key></key><string>x</string></dict></plist>";

int main(void)
{
	prop_dictionary_t d;
	prop_object_t v;
	char *xml;

	printf("[*] control: internalize GOOD key: ");
	d = prop_dictionary_internalize(GOOD_KEY_XML);
	printf("%s (expected)\n", d ? "accepted" : "REJECTED");
	if (d) prop_object_release(d);

	printf("[*] internalize EMPTY key: ");
	d = prop_dictionary_internalize(EMPTY_KEY_XML);
	printf("%s  <-- invariant violated if accepted\n", d ? "ACCEPTED" : "rejected");
	if (d == NULL) { printf("[-] not reproduced\n"); return 1; }

	v = prop_dictionary_get(d, "");
	printf("[%c] prop_dictionary_get(dict, \"\") = %p (empty keysym interned in tree)\n",
	    v ? '+' : '-', (void *)v);

	printf("[*] prop_dictionary_externalize() of the empty-key dict\n");
	printf("    (externalize asserts pdk_key[0] != 0 -- userland assert/abort,\n");
	printf("     kernel INVARIANTS panic)\n");
	fflush(stdout);
	xml = prop_dictionary_externalize(d);
	printf("[*] externalize returned %p\n", (void *)xml);
	if (xml) free(xml);
	return 0;
}