Basic facts about MacOS X kernel extensions
Here are some facts about OS X's kernel extensions (
kexts) that I've managed to aggregate.
Normally, whole directory that contains the kext must be owned by the
root:wheel user. If it's not, you will get errors during loading phase of the kext.
Additionally, your kext must be writable by
root only. If it's not, you will get loading errors!
Be aware that you need to use the
-R option when performing the
chmod command. This means that you need to fix the privileges for all the files and directories inside the kext bundle.
You can dynamically check for conformance to these rules by using the
kextutil tool to load your kext (you can also examine the
-tn -- test and do not load -- option). It's usage is the same as
kextload, so I assume you won't have any problems here.
When writing a new kernel extension it is often a good idea to test it on multiple systems. Fastest way for the developer to perform such tests is to use multiple virtual machines, where each machine is controlled by a different version of the operating system.
Different versions of MacOS X have different policies when it comes to loading thirdparty (i.e. your own) kernel extensions. It is sane to assume that you can't codesign each compilation of your kext, so it's important to know if a system will allow loading unsigned kexts or not.
OS X 10.8 (Mountain Lion, and earlier)
Digitally signed kexts are not allowed. Yes, they're not supported. If you digitally sign a kext file by using an embedded digital sign inside the main kext MachO binary file, the system will refuse to load your kext. So, as far as development requirements goes, you're good to go already!
OS X 10.9 (Mavericks)
Respects codesign, but not enforces it. If your kext is not digitally signed, it still can be loaded (at least by using the
kextload utility). The system can emit a warning with a message that it can't verify the origin of your kext, but it will load it anyway. If you're OK with this message, you're good to go, as a developer. But there's a small catch: if you install inside
/Library/Extensions, you need to have your kext digitally signed. If it's not signed, it will not load.
So, in order to be protected from tampering of your kext in Mavericks, you need to install your kext inside
OS X 10.10 (Yosemite)
Complete enforcement of codesign. Your kext will not be loaded if it's not digitally signed. As a developer, you're screwed.
If you're doing your development on a VM, you can force your system to disable checking of digital signs of every kext. Important thing to note is that it will literally disable the digital sign checking code across the whole system, so don't do it on the computers of your clients!
Disabling is easy. You need to append the
kext-dev-mode=1 option to the boot args of your kernel, by using the
sudo nvram boot-args=kext-dev-mode=1
Please be aware that you need to append this option to your existing boot-args, not overwrite those args (who knows what's in there).
nvram doesn't work in VirtualBox. If you're using VirtualBox, try this command on your host machine:
VBoxManage setextradata <name_of_your_vm> "VBoxInternal2/EfiBootArgs" "kext-dev-mode=1"
If you're using a Hackintosh virtual machine inside VirtualBox that doesn't use EFI (not that I'm using it), and you still can't get it to work, you can also try this one:
You can also insert this option to the
Kernel Flags entry inside this file:
Whatever will be more convinient for you.
OS X 10.11 (El Capitan)
Like Yosemite, complete enforcement of codesign. However, there is a twist: codesign policy on El Capitan is different than on Yosemite. El Capitan introduced something that is called System Integrity Protection, which seems to wrap up some things that were previously used by codesign subsystem alone.
kext-dev-mode=1 option that was previously used to disable kext digital sign enforcement doesn't work anymore. At the time of writing this post, El Capitan is still not fully released, so the method below can change, but it seems that
SIP can be disabled by following these steps:
Booting into Recovery OS (hit
Security Configurationoption, which can be found inside
System Integrity Protectioncheckbox,
Hit Apply and reboot the machine.
Theoretically, it should work. The setting is still saved inside NVRAM, so i'm not sure why they didn't use the same NVRAM option as before, but they seem to had their reasons (I hope).
If, by chance, this won't work, try another method.
Utilities/Terminal, and use
csrutil command to disable
# csrutil status System Integrity Protection status: enabled. # csrutil disable Successfully disabled System Integrity Protection. Please restart the machine for changes to take effect.
However, if you're using VirtualBox, this won't work. You can't simply "enter recovery OS". Instead, you will want to enter "installation OS", or whatever the name is. Follow this article in order to find out how to do it.
macOS 10.15 (Catalina)
Kexts are officially deprecated! Apple says you shouldn't use kexts at all. And if you will still want to use kexts, your application will pop up a message box which user will have to explicitly accept.
You should use Apple's System Extensions or Device Extensions frameworks instead.
Problems with codesign in Mountain Lion (10.8) and earlier OS X versions
Apple suggests that if you would want to retain backward compatibility before Mountain Lion release (10.8), you need to install a signed kext inside
/Library/Extensions, as well as unsigned kext inside
/System/Library/Extensions. OS X versions before Mavericks (10.9) will ignore the signed kext, and load only unsigned kext.
It appears that you can also use a different technique of codesigning of a kext by embedding an external digital sign. To do this, examine the
--no-macho option of
codesign utility. It should place the digital sign externally inside the
_CodeSignature/CodeSignature file. This works, because normally, an internally embedded digital sign is placed inside
LC_CODE_SIGNATURE load command, inside main kext binary. The problem is that older dynamic linkers in older OS X versions can't handle this load command, only new ones can handle it. By placing it outside of the kext binary, you won't confuse older linkers with an unknown load command.