Pinpointing dandling pointers in 3rd party KEXTs

I'm debugging the following kernel panic to do with my custom filesystem KEXT:

panic(cpu 0 caller 0xfffffe004cae3e24): [kalloc.type.var4.128]: element modified after free (off:96, val:0x00000000ffffffff, sz:128, ptr:0xfffffe2e7c639600)

My reading of this is that somewhere in my KEXT I'm holding a reference 0xfffffe2e7c639600 to a 128 byte zone that wrote 0x00000000ffffffff at offset 96 after that particular chunk of memory had been released and zeroed out by the kernel.

The panic itself is emitted when my KEXT requests the memory chunk that's been tempered with via the following set of calls.

zalloc_uaf_panic()

__abortlike
static void
zalloc_uaf_panic(zone_t z, uintptr_t elem, size_t size)
{
...
	(panic)("[%s%s]: element modified after free "
	"(off:%d, val:0x%016lx, sz:%d, ptr:%p)%s",
	zone_heap_name(z), zone_name(z),
	first_offs, first_bits, esize, (void *)elem, buf);
...
}

zalloc_validate_element()

static void
zalloc_validate_element(
	zone_t                  zone,
	vm_offset_t             elem,
	vm_size_t               size,
	zalloc_flags_t          flags)
{
...
	if (memcmp_zero_ptr_aligned((void *)elem, size)) {
		zalloc_uaf_panic(zone, elem, size);
	}
...
}

The panic is triggered if memcmp_zero_ptr_aligned(), which is implemented in assembly, detects that an n-sized chunk of memory has been written after being free'd.

/* memcmp_zero_ptr_aligned() checks string s of n bytes contains all zeros.
 * Address and size of the string s must be pointer-aligned.
 * Return 0 if true, 1 otherwise. Also return 0 if n is 0.
 */
extern int
memcmp_zero_ptr_aligned(const void *s, size_t n);

Normally, KASAN would be resorted to to aid with that. The KDK README states that KASAN kernels won't load on Apple Silicon. Attempting to follow the instructions given in the README for Intel-based machines does result in a failure for me on Apple Silicon.

I stumbled on the Pishi project. But the custom boot kernel collection that gets created doesn't have any of the KEXTs that were specified to kmutil(8) via the --explicit-only flag, so it can't be instrumented in Ghidra. Which is confirmed as well by running:

% kmutil inspect -B boot.kc.kasan
boot kernel collection at /Users/user/boot.kc.kasan
(AEB8F757-E770-8195-458D-B87CADCAB062):

Extension Information:

I'd appreciate any pointers on how to tackle UAFs in kernel space.

Normally, KASAN would be resorted to to aid with that. The KDK README states that KASAN kernels won't load on Apple Silicon. Attempting to follow the instructions given in the README for Intel-based machines does result in a failure for me on Apple Silicon.

Have you tried testing on Intel, either on real hardware or running in a VM?

Beyond that:

I'd appreciate any pointers on how to tackle UAFs in kernel space.

How reproducible is the issue? A lot of your options here depend on how much time/work it takes to create the failure and how "real world" the testing environment needs to be.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Have you tried testing on Intel, either on real hardware or running in a VM?

I haven't. I don't have access to an Intel-based Mac at the moment. And I don't have a VM readily available.

The following write-up[1] on instrumenting KEXTs claims that being able to load a KASAN kernel doesn't mean that one's own KEXT would get instrumented as well. Is that an accurate statement?

[1] https://r00tkitsmm.github.io/fuzzing/2025/04/10/Pishi2.html

How reproducible is the issue?

One issue is only reproducible when mounting my filesystem on an M4 Max CPU, but not on M1 or M2 machines I tried this on.

Another UAF issue is reproducible universally though which manifests itself when attempting to open multiple PDFs at the same time.

Pinpointing dandling pointers in 3rd party KEXTs
 
 
Q