Deciding Whether to Create a Kernel Extension
There are often safer, easier alternatives to creating a kernel extension (kext). It is important to make sure creating a kext is absolutely necessary before doing so.
Make Sure Your Code Needs to Run in Kernel Space
The only reason to write a kext instead of a user-level application or plug-in is to use functionality that is unique to kernel space. The following cases require kernel-resident code:
The primary client of your code resides in the kernel. File-system and networking device drivers fall into this category.
Your code needs to handle a primary interrupt (a CPU interrupt generated by hardware). Many device drivers fall into this category: network controllers, graphics drivers, audio drivers, and so on. A USB or FireWire device driver does not require a kext unless its client resides in the kernel.
A large number of applications require a resource that your code provides.
If your code does not meet any of the above criteria, do not write a kext. Use one of the following user-level solutions instead:
If you are developing a USB or FireWire device driver, I/O Kit provides an interface for communicating with USB and FireWire devices from user space.
If you are developing a persistent background application that does not require kernel permissions, write a daemon.
Proceed with Caution
If you have determined that a kext is the proper solution for your issue, keep in mind that developing a kext is riskier and more difficult than developing a user-level application for many reasons, including the following:
Kexts reduce the memory available to user programs, because kernel-space code requires wired memory (it cannot be paged out).
The kernel runtime environment has many more restrictions than the user space runtime environment, and they must be followed carefully to avoid errors.
Programming errors in a kext are far more severe than bugs in user-level code. Kernel-space code runs in supervisor mode, and it has no protection from memory errors. Consequently, a memory access error in a kext causes a kernel panic, which crashes the operating system.
Debugging kexts is more difficult than debugging user-level programs, because it requires two machines and additional steps to set up a debug session.
For security reasons, some customers restrict the use of third-party kexts.
The Anatomy of a Kernel Extension
Kexts are loadable bundles, and like all loadable bundles, they are loaded dynamically by another application. In the case of a kext, this application is the kernel itself. This has many implications for kexts, such as running in supervisor mode and the ability to load during early boot. Kexts have strict security and location requirements that you need to follow for your kext to work.
To understand the anatomy of a kext, you should have a basic understanding of bundles.
A Kext Bundle Usually Contains Two Main Components
In the most general case, a kext bundle contains two components: an information property list and an executable. Along with these components, a kext bundle may include additional resources and plug-ins. Each of these components is described here.
The Information Property List
A kext’s Info.plist file describes the kext’s contents. Every kext must have an Info.plist file. Because a kext can be loaded during early boot when limited processing is available, this file must be in XML format and cannot include comments. The following keys are of particular importance in a kext’s Info.plist file:
CFBundleIdentifier is used to locate a kext both on disk and in the kernel. Multiple kexts with a given identifier can exist on disk, but only one such kext can be loaded in the kernel at a time.
CFBundleExecutable specifies the name of your kext’s executable, if it has one.
CFBundleVersion indicates the kext’s version. Kext version numbers follow a strict pattern.
OSBundleLibraries lists the libraries (which are kexts themselves) that the kext links against.
IOKitPersonalities is used by an I/O Kit driver for automatically loading the driver when it is needed.
There are several more kext-specific Info.plist keys that allow you to further describe your kext. For a complete discussion of all kext Info.plist keys, including keys that refer to kernel-specific runtime facilities.The Executable
This is your kext’s compiled, executable code. Your executable is responsible for defining entry points that allow the kernel to load and unload the kext. These entry points differ depending on the Xcode template you use when creating your kext. Table 1 describes the default differences between the two kext Xcode templates. This table is intended to illustrate only the most common use of each template; the kernel does not differentiate between kexts created with different templates, and it is possible to incorporate elements of both templates into a kext.
Generic kernel extension template
IOKit driver template
C functions registered as callbacks with relevant subsystems
Subclasses of one or more I/O Kit driver classes, such as IOGraphicsDevice
Start and stop functions with C linkage
C++ static constructors and destructors
Must be loaded explicitly
Loaded automatically by the I/O Kit when needed
Must be unloaded explicitly
Unloaded automatically by the I/O Kit after a fixed interval when no longer needed
Some kexts don’t include an executable. These kexts (called codeless kexts) are typically used to tell I/O Kit to use an existing driver for your device.
Additional Resources and Plug-ins
Kexts sometimes require additional resources, such as firmware for a device. If your kext requires a resource, put it in the Resources folder of your kext’s bundle. If you plan to localize your resources, keep in mind that kernel-space code does not detect localized resources. User-space code does detect localized resources in .lproj subfolders of the Resources folder, so if your resource is accessed only by user-space code, localization is straightforward.
In addition to general resources, kexts can contain plug-ins, including other kexts. If your kext uses a plug-in, put it in the PlugIns folder of your kext’s bundle. Make sure that plug-in kexts do not contain plug-in kexts of their own; only one level of plug-ins is detected in order to limit file system traversal during early boot.
Kernel Extensions Have Strict Security Requirements
Kexts execute in kernel space and run in supervisor mode; consequently, files and folders in a kext bundle must be owned by the root user and the wheel group. Files must have the permissions 0644 , and folders must have the permissions 0755 . A kext that fails to meet these requirements will not load into the kernel.
During development, to ensure that your kext has the proper ownership and permissions, create a copy of your kext as the root user.
This method requires creating a new copy of the kext every time you build it.
Kernel Extensions Should Reside in /System/Library/Extensions
OS X looks up a kext by its CFBundleIdentifier information property list key. Kexts located in /System/Library/Extensions , and the plug-in kexts of those kexts, are searched by default. You can perform a custom search to locate kexts in other folders, but this approach is not recommended. If your kext needs to be loaded during boot loading, it must be installed in /System/Library/Extensions for the operating system to locate it.
Codeless Kernel Extensions Match New Devices to Existing Drivers
A codeless kext is a kext bundle that does not contain an executable. A codeless kext’s IOKitPersonalities dictionary names other kexts that are loaded when a personality matches on a device. Each of these other kexts must have an executable. Codeless kexts are commonly used with USB and HID devices that are driven from user space. Because the kernel driver implements a standard protocol, it can be used by nearly all devices in these categories.
For example, most USB printers share a generic driver provided by Apple, AppleUSBMergeNub.kext . Apple cannot include the matching dictionary for every printer in this kext, so you can install a codeless kext with a personality that matches your printer and set the personality’s CFBundleIdentifier to com.apple.driver.AppleUSBMergeNub . When your printer is attached to the computer, AppleUSBMergeNub.kext is loaded to drive it. Listing 1 shows an example of such a codeless kext’s IOKitPersonalities dictionary, in XML format.
Listing 1 The IOKitPersonalities dictionary of a codeless kext
Creating a Generic Kernel Extension with Xcode
In this tutorial, you learn how to create a generic kernel extension (kext) for OS X. You create a simple kext that prints messages when loading and unloading. This tutorial does not cover the process for loading or debugging your kext—see Debugging a Kernel Extension with GDB after you have completed this tutorial for information on loading and debugging.
If you are unfamiliar with Xcode, first read Xcode Quick Tour Guide
Create a New Project
Creating a kext project in Xcode is as simple as selecting the appropriate project template and providing a name.
Choose File > New > New Project. The New Project panel appears.
In the New Project panel, select System Plug-in from the list of project categories on the left. Select Generic Kernel Extension from the list of templates on the right. Click Next.
In the screen that appears, enter MyKext for the product name, enter a company identifier, and click Next.
Choose a location for the project, and click Create.
Xcode creates a new project and displays its project window. You should see something like this:
The new project contains several files, including a source file, MyKext.c , that contains templates for the kext’s start and stop functions.
Make sure the kext is building for the correct architectures.
(If you don’t see the screen above, select MyKext under Targets. Select the Build Settings tab. Click the disclosure triangle next to Architectures.)
Next to Build Active Architecture Only make sure to select No—this is especially important if you are running a 32-bit kernel on a 64-bit machine.
Implement the Start and Stop Functions
Now that you’ve created the project, it’s time to make your kext do something when it gets loaded and unloaded. You’ll do so by adding code to your kext’s start and stop functions, which are called when your kext is loaded and unloaded.
Implement the Start and Stop Functions
Open MyKext.c to edit the start and stop functions.
Figure 1 shows the unedited file.
Figure 1 Viewing source code in Xcode
The default start and stop functions do nothing but return a successful status. A real kext’s start and stop functions typically register and unregister callbacks with kernel runtime systems, but for this tutorial, your kext simply prints messages so that you can confirm when your kext has been started and stopped.
Edit MyKext.c to match the code in Listing 1 .
Listing 1 MyKext.c file contents
Notice that MyKext.c includes two header files, <sys/systm.h> and <mach/mach_types.h> . Both header files reside in Kernel.framework . When you develop your own kext, be sure to include only header files from Kernel.framework (in addition to any header files you create), because only these files have meaning in the kernel environment. If you include headers from outside Kernel.framework , your kernel extension might compile, but it will probably fail to load or run because the functions and services those headers define are not available in the kernel.
Save your changes by choosing File > Save.
Edit the Information Property List
Like all bundles, a kext contains an information property list, which describes the kext. The default Info.plist file created by Xcode contains template values that you must edit to describe your kext.
A kext’s Info.plist file is in XML format. Whenever possible, you should view and edit the file from within Xcode or within the Property List Editor application. In this way, you help ensure that you don’t add elements (such as comments) that cannot be parsed by the kernel during early boot.
Click Info.plist in the Xcode project window.
Xcode displays the Info.plist file in the editor pane. You should see the elements of the property list file, as shown in Figure 2 .
By default, Xcode’s property list editor masks the actual keys and values of a property list. To see the actual keys and values, Control-click anywhere in the property list editor and choose Show Raw Keys/Values from the contextual menu.
Change the value of the CFBundleIdentifier property to use your unique namespace prefix.
On the line for CFBundleIdentifier , double-click in the Value column to edit it. Select com.yourcompany and change it to com.MyCompany (or your company’s DNS domain in reverse). The value should now be com.MyCompany.kext.$
Bundles in OS X typically use a reverse-DNS naming convention to avoid namespace collisions. This is particularly important for kexts because all loaded kexts share a single namespace for bundle identifiers.
The last portion of the default bundle identifier, $
Save your changes by choosing File > Save.
Build the Kernel Extension
Now you’re ready to configure your build settings and build your kext to make sure the source code compiles. First, configure your build settings to build the kext for every architecture, to make sure your kext will load regardless of the architecture of the kernel.
Click the disclosure triangle next to Targets in the Groups and Files pane.
Select the MyKext target.
Choose File > Get Info. The Target “MyKext” Info window opens.
In the list of settings, find Build Active Architecture Only and make sure the checkbox is unchecked.
Close the Target MyKext Info window.
Now that your kext is building against every architecture, choose Build > Build to build your project. If the build fails, correct all indicated errors and rebuild before proceeding.
Add Library Declarations
Because kexts are linked at load time, a kext must list its libraries in its information property list with the OSBundleLibraries property. At this stage of creating your kext, you need to find out what those libraries are. The best way to do so is to run the kextlibs tool on your built kext and copy its output into your kext’s Info.plist file.
Run kextlibs on the Kernel Extension
kextlibs is a command-line program that you run with the Terminal application. Its purpose is to identify libraries that your kext needs to link against.
Note: This tutorial uses the dollar sign ( $ ) prompt when it shows the commands you type in the Terminal application. This is the default prompt of the bash shell, which is the default shell in OS X. If you’re using a different shell, you may see a different prompt (the percent symbol ( % ) is another common prompt).
Start the Terminal application, located in /Applications/Utilities .
In the Terminal window, move to the directory that contains your kext.
Xcode stores your kext in the Debug folder of the build folder of your project (unless you’ve chosen a different build configuration or set a different location for build products using Xcode’s Preferences dialog).
This directory contains your kext. It should have the name MyKext.kext . This name is formed from the Product Name as set in your target’s build settings, and a suffix, in this case .kext .
Run kextlibs on your kernel extension with the -xml command-line flag.
This command looks for all unresolved symbols in your kernel extension’s executable among the installed library extensions (in /System/Library/Extensions/ ) and prints an XML fragment suitable for pasting into an Info.plist file. For example:
Make sure kextlibs exited with a successful status by checking the shell variable $? .
If kextlibs prints any errors or exits with a nonzero status, it may have been unable to locate some symbols. For this tutorial, the libraries are known, but in general usage you should use the kextfind tool to find libraries for any symbols that kextlibs cannot locate. See Locate Kexts for information on kextfind .
Select the XML output of kextlibs and choose Edit > Copy.
Add the Library Declarations to the Information Property List
Earlier, you edited the information property list with Xcode’s graphical property list editor. For this operation, however, you need to edit the information property list as text.
Control-click Info.plist in the Xcode project window, then choose Open As > Source Code File from the contextual menu.
Xcode displays the Info.plist file in the editor pane. You should see the XML contents of the property list file, as shown in Figure 3 . Note that dictionary keys and values are listed sequentially.
Figure 3 MyKext Info.plist as text
Select all the lines defining the empty OSBundleLibraries dictionary:
Paste text into the info dictionary.
If kextlibs ran successfully, choose Edit > Paste to paste the text you copied from Terminal.
If kextlibs didn’t run successfully, type or paste this text into the info dictionary:
Save your changes by choosing File > Save.
Choose Build > Build a final time to rebuild your kext with the new information property list.
Prepare the Kernel Extension for Loading
Now you are ready to prepare your kext for loading. You do this with the kextutil tool, which can examine a kext and determine whether it is able to be loaded. kextutil can also load a kext for development purposes, but that functionality is not covered in this tutorial.
Note: This tutorial does not cover actually loading a kext. For safety reasons, you should not load your kext on your development machine. For information on loading and debugging a kext with a two-machine setup, see Debugging a Kernel Extension with GDB .
Set the Kernel Extension’s Permissions
Kexts have strict permissions requirements. The easiest way to set these permissions is to create a copy of your kext as the root user. Type the following into Terminal from the proper directory and provide your password when prompted:
Now that the permissions of the kext’s temporary copy are correct, you are ready to run kextutil .
Type the following into Terminal:
The -n (or -no-load ) option tells kextutil not to load the driver, and the -t (or -print-diagnostics ) option tells kextutil to print the results of its analysis to Terminal. If you have followed the previous steps in this tutorial correctly, kextutil indicates that the kext is loadable and properly linked.
Note: You may encounter an error similar to the following: