Secure Kernel Extension Loading in macOS High Sierra

0x00 Background

Reference:
Technical Note TN2459: Secure Kernel Extension Loading

In macOS High Sierra, Apple introduced Secure Kernel Extension Loading (aka Kext User Consent) feature to require user confirmation before loading a signed kext.
Note that this restriction only apply to valid signed kexts. Unsigned kexts would be taken care of by kext signing checking in System Integrity Protection. And if kext signing checking is disabled, the kext user consent feature will also be turned off.

For the configuration of this feature, as described in the tech notes, begin with 10.13 Dev Beta 3/Public Beta 2, spctl tool can be used in Recovery environment to modify kext user consent settings:

Kernel Extension User Consent Usage:
    spctl kext-consent <action>         ** Modifications only available in Recovery OS **
        status
            Print whether kernel extension user consent is enabled or disabled.
        enable
            Enable requiring user consent for kernel extensions.
        disable
            Disable requiring user consent for kernel extensions.
        add <team-id>
            Insert a new Team Identifier into the list allowed to load kernel extensions without user consent.
        list
            Print the list of Team Identifiers allowed to load without user consent.
        remove <team-id>
            Remove a Team Identifier from the list allowed to load kernel extensions without user consent.

0x01 Take a look at spctl

Behind the scenes, modify kext user consent setting by spctl would change the SIP configuration, which is persisted by writing into NVRAM (csr-active-config/csr-data).

The newly added CSR flag can be used to disable/enable kext consent feature:

// spctl kext-consent disable => set csr-active-config = 0x0200
#define CSR_ALLOW_UNAPPROVED_KEXTS        (1 << 9)    //added in 10.13

As for add/remove/list team-id feature provided by spctl, csr-data comes to the party in this case:

<!-- dump from csr-data -->

<dict>
    <key>kext-allowed-teams</key>
    <array>
        <string>TEAMID</string>
    </array>
</dict>
%00

This list acts as a whitelist for all allowed team-ids, which could be preset for enterprise use.

And apparently, spctl also got the com.apple.private.iokit.nvram-csr entitlement as csrutil:

Executable=/usr/sbin/spctl
??qq?<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>com.apple.private.iokit.nvram-csr</key>
	<true/>
</dict>
</plist>

0x02 Going deeper

If spctl is still not good enough for you, just play with the newly added kext policy database.

-> List user approved kexts:

sudo sqlite3 /var/db/SystemPolicyConfiguration/KextPolicy "SELECT team_id,bundle_id,allowed,developer_name,flags from kext_policy"

-> Approved entries from MDM profile:

sudo sqlite3 /var/db/SystemPolicyConfiguration/KextPolicy "SELECT team_id,bundle_id,allowed,payload_uuid from kext_policy_mdm"

-> Check approved kexts load history:

sudo sqlite3 /var/db/SystemPolicyConfiguration/KextPolicy "SELECT path,team_id,bundle_id,boot_uuid,created_at,last_seen,flags from kext_load_history_v3"

By default, the kext policy database is read-only for normal boot due to filesystem protection in SIP. In order to make changes, turn off the filesystem protection first:

csrutil enable --without fs --no-internal

Or, just modify the database directly in Recovery OS.

-> Remove certain team-id. Kext signed with it would require user consent again next time:

# In Recovery OS, chroot to your system volume. 
# May also need to unlock it first.
chroot /Volumes/Macintosh\ HD/
sqlite3 /var/db/SystemPolicyConfiguration/KextPolicy "DELETE FROM kext_policy WHERE team_id = 'TEAM_ID'"

…even a plist for allowed codeless kexts? LoL.

/var/db/SystemPolicyConfiguration/Default.plist

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.