⬢ DragonFlyBSD Kernel Audit
DF-5102 / df5102_nullfree.c
← back to finding ↓ download raw
/*
 * DF-5102 mechanism PoC: apple_fw_probe() (sys/dev/apple/fw/apple_fw.c:107-113)
 * does:
 *
 *	product = kgetenv("smbios.system.product");
 *	biosver = kgetenv("smbios.bios.version");
 *	...
 *	kfreeenv(product);
 *	kfreeenv(biosver);
 *
 * kgetenv() returns NULL when the variable is absent and the kernel
 * environment is dynamic (kern_environment.c:228-251; kenv_isdynamic=1 is
 * the standard post-loader state, kern_environment.c:592).
 * kfreeenv() unconditionally calls kfree(env, M_KENV) when kenv is dynamic
 * (kern_environment.c:331-336), and DragonFly's _kfree() panics on NULL:
 * kern_slaballoc.c:1407-1408  "trying to free NULL pointer".
 *
 * This module reproduces the exact sink with a definitely-missing variable,
 * the same situation apple_fw_probe faces on APPLE-firmware hardware whose
 * smbios.* environment entries are absent.
 */
#include <sys/param.h>
#include <sys/module.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/malloc.h>

static int
df5102_load(module_t mod, int what, void *arg)
{
	char *product, *biosver;

	switch (what) {
	case MOD_LOAD:
		kprintf("DF5102: enter\n");
		/*
		 * Use names that are absent from the kernel environment.
		 * On hardware meeting the finding's precondition (FADT
		 * OemId "APPLE " but no SMBIOS-derived kenv entries),
		 * kgetenv("smbios.system.product") returns NULL exactly
		 * like these absent names do, and apple_fw.c:112-113 then
		 * feeds that NULL to kfreeenv().
		 */
		product = kgetenv("smbios.system.product.absent");
		biosver = kgetenv("smbios.bios.version.absent");
		kprintf("DF5102: product=%p biosver=%p (NULL == kenv entry absent)\n",
		    product, biosver);
		if (product == NULL || biosver == NULL)
			kprintf("DF5102: precondition met, calling kfreeenv as "
			    "apple_fw.c:112-113 does -- expect panic\n");
		kfreeenv(product);
		kfreeenv(biosver);
		kprintf("DF5102: survived (kenv static or vars present?)\n");
		return (0);
	case MOD_UNLOAD:
		return (0);
	default:
		return (EOPNOTSUPP);
	}
}

static moduledata_t df5102_mod = { "df5102b", df5102_load, NULL };
DECLARE_MODULE(df5102b, df5102_mod, SI_SUB_DRIVERS, SI_ORDER_ANY);