skip to content

On macOS, what is a kernel extension (kext), and why has Apple pushed third-party drivers out of the kernel into System Extensions and DriverKit?

level: middleimportance: should knowfreq 40%

answer

  1. code linked into the running kernel
  2. IOKit classes plus a matching plist
  3. a driver bug becomes a panic
  4. same role, userspace process instead
  5. restartable, entitlement-gated

basics

~20 s

A kext is code loaded into the XNU kernel's own address space, historically an IOKit driver or a filesystem. Because a defect there panics or compromises the whole machine, Apple deprecated third-party kexts in favour of System Extensions and DriverKit, which run the same logic as userspace processes.

solid answer

~50 s

A kernel extension is a bundle of code loaded into XNU itself — most often an IOKit driver written in the restricted C++ dialect that `libkern` supports, matched to hardware by *personalities* declared in the bundle's `Info.plist` rather than by code. Running inside the kernel means full privilege and no isolation: a null dereference panics the machine, a bug is a kernel-level vulnerability, and a badly written kext degrades everything. From macOS 10.15 Apple deprecated third-party kexts and introduced **System Extensions** — `DriverKit` extensions for drivers, plus Endpoint Security and Network Extension providers — which run as ordinary userspace processes with an IOKit-shaped API. A crashing DriverKit extension is restarted instead of taking the host down. Loading a kext today also requires explicit user approval and, on Apple Silicon, lowering the machine's security setting and rebooting, so shipping one is an operational burden as well as a risk.

code

bash · 2 lines
bash
kmutil showloaded
systemextensionsctl list

go deeper

for a junior

Know that a kext is code loaded into the kernel itself, that it is usually a driver, and that Apple now steers developers to System Extensions that run in userspace instead.

for a middle

Explain the IOKit object model and plist-based personality matching, and give the concrete reason for the migration: an in-kernel fault is a panic while a userspace extension can simply be restarted.

for a senior

Bring operational reality: approving and deploying a kext across a fleet, the Apple Silicon reduced-security requirement and reboot, upgrade breakage from kernel-internal symbols, and how you would plan a vendor migration.

for a principal

Own the strategy question of depending on any third-party kernel code at all. Weigh vendor capability against fleet risk and upgrade cadence, and treat Apple-granted entitlements as a supply-chain dependency in the decision.

## What a kext is A **kernel extension** is a loadable bundle of code that becomes part of the running XNU kernel. Historically kexts covered three things: device drivers, filesystems, and network/security filters. Once loaded, kext code runs at kernel privilege in the kernel's address space with no memory protection separating it from anything else in the kernel. Most kexts are **IOKit** drivers. IOKit is an object-oriented driver framework written in a restricted C++ dialect provided by `libkern`: driver classes derive from `OSObject` and `IOService`, and the runtime uses `OSMetaClass` for type information because the usual C++ features that a kernel cannot afford — exceptions, RTTI, multiple inheritance — are unavailable. A driver implements the service lifecycle, principally `probe`, `start` and `stop`. ## Matching: data, not code The part that surprises engineers coming from Linux is how a driver is bound to hardware. There is no `modprobe` alias table and no `udev` rule. Each kext declares **personalities** in its `Info.plist` under `IOKitPersonalities`, naming an `IOProviderClass` (the kind of parent object it attaches to), an `IOClass` (the C++ class to instantiate) and matching keys for the device. When XNU discovers hardware it publishes a nub in the **I/O Registry**, scores all candidate personalities, and starts the best match. You can inspect that live tree with `ioreg`. Driver matching is therefore declarative data, evaluated at runtime. ## Why the kernel is a bad place for third-party code The case against kexts is straightforward and worth stating in the interview as consequences, not adjectives: - **Reliability.** A bug that would be a segfault in a userspace process is a **kernel panic**. One vendor's driver takes the whole machine down, mid-flight, with unsaved work. - **Security.** A kext runs with the highest privilege in the system. A vulnerability in it is a full system compromise, and it is a natural target for attackers who cannot beat the platform's own defences. - **Compatibility.** Kexts link against kernel-internal symbols that Apple is free to change. Every OS update risks breaking them, which historically blocked users from upgrading. - **Architecture churn.** In-kernel code must be native for the CPU; there is no compatibility translation layer inside the kernel. ## The replacement: System Extensions and DriverKit From macOS 10.15 Apple deprecated third-party kexts and shipped **System Extensions**: bundles delivered inside an application that run as **userspace** processes but occupy the roles kexts used to. - **DriverKit** extensions ("dexts") implement device drivers using an API deliberately shaped like IOKit — familiar class names and lifecycle — but executing outside the kernel with a restricted set of entitlements. - **Endpoint Security** replaces in-kernel security/monitoring filters for EDR and anti-malware products. - **Network Extension** replaces in-kernel network filters, content filters and VPN plugins. The engineering payoff: a crash is a process crash, and the extension can be restarted rather than panicking the host; a compromise is contained by the process boundary and the extension's entitlements; and the API is a supported contract instead of kernel-internal symbols. The cost, which an honest answer should acknowledge: DriverKit exposes a subset of what the kernel could do, so some device classes still cannot be expressed; there is a cross-boundary cost for very high-throughput or latency-critical hardware; and each extension type requires an entitlement granted by Apple, so the vendor's ability to ship is gated on the platform owner. ## Where kexts stand today Since macOS 11 the kernel and its bundled extensions are prelinked into **kernel collections** — a boot collection built at install/update time, with auxiliary collections for approved third-party kexts — managed by `kmutil`. The older per-load tools are deprecated. Loading a third-party kext now requires explicit user approval, and on Apple Silicon it additionally requires lowering the machine's startup security level and rebooting, which for a fleet means touching every device. That operational friction is itself the point: Apple made the in-kernel path expensive so vendors migrate. ```bash kmutil showloaded # kexts currently in the kernel systemextensionsctl list # userspace system extensions installed ``` ## How to answer well Define a kext in one sentence, name IOKit and the `Info.plist` matching model to show you know what one actually contains, then give the reliability/security argument in terms of a panic versus a restartable process. Finish with the honest tradeoff — reduced capability and Apple-gated entitlements — rather than presenting the migration as pure upside.

  • How does IOKit decide which driver claims a newly discovered device?
    By matching declarative data, not code. Each candidate kext declares personalities in its `Info.plist` naming an `IOProviderClass`, an `IOClass` and device-matching keys. When the kernel publishes a nub for the hardware in the I/O Registry, it scores the candidate personalities and starts the winning one, calling `probe` and then `start` on the instantiated class.
  • What is the practical difference in failure behaviour between a kext and a DriverKit extension?
    A kext runs in the kernel address space, so an invalid memory access is a kernel panic and the whole machine goes down. A DriverKit extension is a userspace process: the same bug kills only that process, which the system can relaunch, and the fault is contained by the process boundary and the extension's entitlements.
  • Why can a vendor not always migrate a kext to DriverKit?
    DriverKit exposes a deliberately restricted subset of what in-kernel IOKit could do, so some device classes and low-level behaviours have no supported equivalent. Very latency- or throughput-sensitive hardware may also suffer from crossing the userspace boundary. On top of that, each extension type needs an entitlement granted by Apple, so shipping is gated by the platform owner.

saying these in an interview costs you the question

  • Treating a kext as just a userspace daemon
  • Assuming kext matching works like udev rules
  • Claiming a driver crash only kills the driver
  • Saying DriverKit is a full replacement for every kext
  • Believing kexts can still be loaded silently without approval

context