- Question: Q: What exactly is syspolicyd and why is it running all the time?
- Helpful answers
- syspolicyd internals
- Categories
- Overview
- Startup
- Gatekeeper
- Services
- com.apple.security.syspolicy
- assess
- update
- record
- cancel
- check-dev-id
- check-notarized
- ticket-register
- ticket-lookup
- Clients
- Security.framework
- KextManager
- Services
- com.apple.security.syspolicy.kext
- No entitlements needed
- com.apple.rootless.kext-secure-management
- com.apple.private.security.syspolicy.kext-policy-management
- com.apple.private.security.syspolicy.mdm-kext-policy-management
- Clients
- SystemPolicy.framework
- ExecManager
- Services
- com.apple.security.AppleSystemPolicy.mig
- notify_32bit_exec
- notify_32bit_mmap
- log_platform_binary
- log_executable
- com.apple.security.syspolicy.exec
- Clients
- AppleSystemPolicy.kext
- SystemPolicy.framework
- launchd
- com.apple.security.syspolicy.report
- com.apple.security.syspolicy.find.bundles
- com.apple.security.syspolicy.measure
- com.apple.security.syspolicy.kext.mt
- com.apple.security.syspolicy.rearm
- Miscellaneous
- Entitlements
- Defaults
- com.apple.security.syspolicy.KextPolicyForceEnable
- com.apple.security.syspolicy.ExecutableMeasurementDisable
- com.apple.security.syspolicy.ExecutableMeasurementDisableFullValidation
- com.apple.security.syspolicy.ExecutableMeasurementDisableCalculateFMJ
- com.apple.security.GKAutoRearm
- Revision History
Question: Q: What exactly is syspolicyd and why is it running all the time?
Recently I installed the Catalina supplemental update for 10.15.7 with built number 19H15. However after I installed the update I notice that a process called syspolicyd is almost always running at the top of the list in Activity Monitor. And every time when it runs it consumes quite a bit of CPU usage, drains the battery and writes a lot on my disk. I only took a notice of it since my MacBook Air 2019 fan was on when just in stand by (idle) so it was very odd. So does anyone here knows what exactly is syspolicyd and why is it running all the time? And is there any fix for it?
MacBook Air 13″, macOS 10.15
Posted on Dec 5, 2020 11:51 PM
Helpful answers
Very informative, though I think this is a bug since it really drains my battery. And I also study the problem and I found out that if I restart my computer and use it, syspolicyd will not appear, it might appear the first 30 seconds from startup or when I launch an app, but it will eventually go away. But when I close my lid (which automatically lock my computer) and reopened it and signed back in, syspolicyd will keep on running for like a minute, and will come back in an average of 5 to 6 minutes. So I think it has something to do with closing the lid or logging out or both.
Dec 6, 2020 3:04 PM
syspolicyd was originally introduced in macOS 10.7.3 with the Gatekeeper feature. Its original purpose was to act as the centralized daemon for answering Gatekeeper questions. Today it still serves that purpose but its scope has greatly expanded. In addition to assessing applications before running, the daemon also handles authorizing the loading of KEXTs as well as tracking legacy applications that the user has run. In Mojave syspolicyd has expanded again and is responsible for handling software notarization checks as well. We’ll start with a very high level look at the daemon startup process and then dive deeper into each of syspolicyd’s subsystems.
Dec 6, 2020 9:52 AM
There’s more to the conversation
Loading page content
Page content loaded
syspolicyd was originally introduced in macOS 10.7.3 with the Gatekeeper feature. Its original purpose was to act as the centralized daemon for answering Gatekeeper questions. Today it still serves that purpose but its scope has greatly expanded. In addition to assessing applications before running, the daemon also handles authorizing the loading of KEXTs as well as tracking legacy applications that the user has run. In Mojave syspolicyd has expanded again and is responsible for handling software notarization checks as well. We’ll start with a very high level look at the daemon startup process and then dive deeper into each of syspolicyd’s subsystems.
Источник
syspolicyd internals
Categories
With my previous post I took a look at the SystemPolicy.framework and how it kept track of 32-bit applications that had been run. In the process of looking into that I ended up looking into the internals of syspolicyd . Way back in macOS 10.10.5 syspolicyd was part of the security_systemkeychain source code that Apple releases with each version of macOS. Unfortunately since that time syspolicyd was moved out of the security_systemkeychain package and closed sourced. This post details the internals of syspolicyd as it is today in macOS 10.14.x and covers both what services it provides and what clients connect and use its functionality.
Overview
syspolicyd was originally introduced in macOS 10.7.3 with the Gatekeeper feature. Its original purpose was to act as the centralized daemon for answering Gatekeeper questions. Today it still serves that purpose but its scope has greatly expanded. In addition to assessing applications before running, the daemon also handles authorizing the loading of KEXTs as well as tracking legacy applications that the user has run. In Mojave syspolicyd has expanded again and is responsible for handling software notarization checks as well. We’ll start with a very high level look at the daemon startup process and then dive deeper into each of syspolicyd ’s subsystems.
Startup
The startup process of the syspolicyd daemon is not very complex. The entire main function was outlined in my previous article. Here it is in its entirety:
Conceptually you can think of syspolicyd as being composed on three main subsystems:
When launchd starts up syspolicyd each subsystem goes through and initializes itself. They set up database connections, XPC services and activities and even a MIG service. Each subsystem is detailed out in the sections below
Gatekeeper
Gatekeeper is a technology that helps ensure you only run software from the app store and trusted developers. It’s responsible for checking the code signing attributes on applications downloaded from the internet.
Services
com.apple.security.syspolicy
Based on the previously open sourced syspolicyd.cpp code, we can easily get a sense of how this XPC service works. Essentially the service checks the incoming XPC message dictionary for what function is sent over. If the function sent over is known then the corresponding function implementation is called. Otherwise if the function isn’t passed or is unknown then an error is returned to the XPC client. The following function values are currently defined as of macOS Mojave:
Most of these functions call into the Security.framework to do the real work. Which can be somewhat confusing since we’ll see later that the Security.framework is one of the primary clients of this service. The framework is set up in such a way that when regular processes call into its APIs it will send an XPC request to this service and when this service runs it will run the PolicyEngine directly inside of syspolicyd using the frameworks code.
assess
Calls into SecAssessmentCreate passing in the kSecAssessmentFlagDirect flag so that the policy engine runs in process. The PolicyEngine::evaluate method is then called. This method asks the system for its assessment of a proposed operation. A CFURL is passed in describing the file central to the operation. The operation defaults to assessing whether the file can be executed or not but there are also options for evaluating if software can be installed or a document can be opened.
update
Calls into SecAssessmentCopyUpdate which will then in turn call into PolicyEngine::update . This method is responsible for making changes to the system policy configuration. The configuration gets stored in a sqlite3 database in /var/db/SystemPolicy .
record
This method is called into through SecAssessmentControl with the operation value being passed in as ui-record-reject-local . This method will do a check to ensure the caller holds the com.apple.private.assessment.recording entitlement before calling into PolicyEngine::recordFailure . This writes the failure out to the /var/db/.LastGKReject file.
cancel
Cancels an in progress assessment request.
check-dev-id
This method will check whether Gatekeeper allows apps from identified developers. SecAssessmentControl is called with the operation ui-get-devid-local passed in. This will in turn run the following query on the /var/db/SystemPolicy database.
Even though there can be multiple records returned from this query, the PolicyEngine simply returns false if the value of disabled is 1 otherwise it returns true.
check-notarized
This is similar to check-dev-id . It will check whether Gatekeeper allows notarized applications to run. This again calls SecAssessmentControl this time passing in the ui-get-notarized-local option. This in turn runs the following query:
If disabled is 1 then the PolicyEngine returns false otherwise it returns true.
ticket-register
When the system is validating binaries it will attempt to register stapled notarization tickets it finds with the system. This service function ultimately handles those calls. The data passed in gets turned into a GKTicket object and then validated. If the ticket is validated then the following query is run to insert the information into the /var/db/SystemPolicyConfiguration/Tickets sqlite3 database.
ticket-lookup
This function is responsible for retrieving ticket information. It can either retrieve the information from the locally stored copy in /var/db/SystemPolicyConfiguration/Tickets or it can query a web service at Apple to lookup that information. In some cases when the Security.framework wants to check if a ticket is revoked it will force the lookup in the web service provided by Apple. Here’s an example of the query checking for a local copy of the ticket:
And here’s an example of a lookup of a ticket in the web service:
Clients
Security.framework
The Security.framework is the primary client of this service with all of its SecAssessment APIs. As mentioned above if you call into these APIs outside of syspolicyd then the framework will use XPC to request the information from syspolicyd . Here’s a short overview of the SecAssessment APIs:
API | Description |
---|---|
SecAssessmentCreate | Ask the system for its assessment of a proposed operation. |
SecAssessmentCopyUpdate | Make changes to the system policy configuration. |
SecAssessmentControl | Miscellaneous system policy operations. |
SecAssessmentTicketRegister | Registering stapled ticket with system. |
SecAssessmentTicketLookup | Check whether software is notarized. |
Luckily the Security.framework is still open sourced, so you can look more into the internals of these APIs here:
Additionally if you’re looking for a short sample of how the Security.framework makes the XPC calls to call into the Gatekeeper XPC service, I have some short example code here.
This means that if we really want to find out what clients use this service we should search the system for users of the SecAssessment APIs. I used ripgrep on a Mojave system to search for binaries that used SecAssessment and found the following items:
- /Applications/Utilities/Script Editor.app/Contents/MacOS/Script Editor
- /System/Library/CoreServices/CoreServicesUIAgent.app/Contents/MacOS/CoreServicesUIAgent
- /System/Library/CoreServices/Installer.app/Contents/MacOS/Installer
- /System/Library/Frameworks/Automator.framework/Versions/A/Automator
- /System/Library/Frameworks/JavaVM.framework/Versions/A/Frameworks/JavaRuntimeSupport.framework/Versions/A/JavaRuntimeSupport
- /System/Library/Frameworks/Security.framework/Versions/A/Security
- /System/Library/PreferencePanes/Security.prefPane/Contents/MacOS/Security
- /System/Library/PrivateFrameworks/ConfigurationProfiles.framework/XPCServices/SystemPolicyService.xpc/Contents/MacOS/SystemPolicyService
- /System/Library/PrivateFrameworks/PackageKit.framework/Versions/A/PackageKit
- /System/Library/PrivateFrameworks/SystemAdministration.framework/XPCServices/writeconfig.xpc/Contents/MacOS/writeconfig
- /System/Library/PrivateFrameworks/XprotectFramework.framework/Versions/A/XPCServices/XprotectService.xpc/Contents/MacOS/XprotectService
- /usr/libexec/mdmclient
- /usr/libexec/syspolicyd
- /usr/sbin/spctl
KextManager
The KextManager subsystem plays a role in user-approved kernel extension loading. The following Objective-C classes make up the core of the KextManager subsystem:
- KextManagerService
- KextManagerPolicy
- KextManagerDatabase
- KextManagerUI
The diagram below shows the flow of a typical request to load a kernel extension all the way to the point of notifying the user about it.
Services
com.apple.security.syspolicy.kext
This XPC service is defined in the syspolicyd launchd plist. It’s the primary way clients can check on and update what kernel extensions have been approved to load. Since it’s written in Objective-C it makes use of the NSXPCInterface and NSXPCListener classes. The NSXPCInterface is defined to implement the following protocol:
The KextManagerService class is then responsible for implementing this protocol. Since KEXT loading is a sensitive system operation there are a handful of different permissions and entitlements needed to call into this XPC service. I’ll break down my description of the services functionality by the entitlements needed to call into the different methods.
No entitlements needed
copyPendingApprovalsWithReply:
This method will retrieve the list of KEXTs that attempted to load but have not been approved yet from the /var/db/SystemPolicyConfiguration/KextPolicy sqlite3 database.
copyCurrentPolicyWithReply:
Provides a list of all KEXTs stored in the /var/db/SystemPolicyConfiguration/KextPolicy database.
teamIdentifierIsAllowed:withReply:
Determines if a specific team identifier is allowed by the /var/db/SystemPolicyConfiguration/KextPolicy database.
com.apple.rootless.kext-secure-management
- canLoadKernelExtensionInCache:withReply:
- canLoadKernelExtension:withReply:
Both of these methods end up doing the same thing. They call into the KextManagerPolicy object calling the canLoadKernelExtensionAtURL:isCacheLoad: selector. These are the main methods responsible for determining if a KEXT can be loaded. It will check if the KEXT is allowed by MDM or approved by the user.
com.apple.private.security.syspolicy.kext-policy-management
- updatePolicyItems:withReply:
This method gets used when a KEXT is actually approved to update the record in the /var/db/SystemPolicyConfiguration/KextPolicy database.
com.apple.private.security.syspolicy.mdm-kext-policy-management
setUserApprovalAllowed:withReply:
Allows MDM to determine whether a user can approve a KEXT from the System Preferences or only the MDM whitelist is allowed.
installMDMPayload:withTeams:andExtensions:withReply:
Parses the MDM KEXT policy payload and updates the kext_policy_mdm table in the /var/db/SystemPolicyConfiguration/KextPolicy database.
removeMDMPayload:withReply:
Removes an existing MDM KEXT Policy from the /var/db/SystemPolicyConfiguration/KextPolicy database.
Clients
If you attempt to find clients of this service by searching for users of the KernelExtensionManager protocol you’re only going to find a single client, the SystemPolicy.framework .
SystemPolicy.framework
So in order to find the true clients we need to search the system for the binaries making use of the SPKernelExtensionPolicy class from the SystemPolicy.framework . Doing that results in the following list:
- /System/Library/PreferencePanes/Security.prefPane/Contents/MacOS/Security
- /System/Library/PrivateFrameworks/ConfigurationProfiles.framework/XPCServices/ExecutionPolicyService.xpc/Contents/MacOS/ExecutionPolicyService
- /System/Library/SystemProfiler/SPDisabledApplicationsReporter.spreporter/Contents/MacOS/SPDisabledApplicationsReporter
- /sbin/kextload
- /usr/bin/kextutil
- /usr/libexec/amfid
- /usr/libexec/kextd
- /usr/libexec/syspolicyd
- /usr/sbin/kextcache
- /usr/sbin/spctl
ExecManager
As opposed to the KextManager subsystem the ExecManager subsystem actually has multiple services that it provides. One is an XPC service that has a similar architecture to the KextManagerService and the other is a MIG service that provides communication with the kernel. The core of the subsystem is made up of the following Objective-C classes:
- ExecManagerService
- ExecManagerPolicy
- ExecManagerDatabase
Unlike the KextManagerPolicy which has a helper class to notify the user through the UI, the ExecManagerPolicy class coordinates with the CoreServices.framework to notify the user of the launch of deprecated 32-bit executables.
Services
com.apple.security.AppleSystemPolicy.mig
Looking at the launchd plist for syspolicyd we see that this service is actually a MachService . Additionally it’s defined to provide its service using HostSpecialPort 29. Looking at the ExecManagerService class we see that there’s a method called startMIGService that is responsible for calling bootstrap_check_in to notify launchd the service is available. I created a short Hopper script called MIG Detect.py to find and label the different MIG messages that were being used.
notify_32bit_exec
notify_32bit_mmap
Both of these functions take similar actions. They call into the ExecManagerService and call the notify32bitExecForUser method. This will in turn save the information into the /var/db/SystemPolicyConfiguration/ExecPolicy sqlite3 database in the legacy_exec_history_v4 table.
log_platform_binary
This method will call into the ExecManagerService and call the logOldPlatformBinary method. This will in turn create a AWDSystemPolicyOldPlatformBinary object and then call AWDPostMetric which is actually part of the private WirelessDiagnostics.framework . This private framework apparently collects more than just wireless diagnostics. Additionally a record gets added into the old_platform_cache table in the /var/db/SystemPolicyConfiguration/ExecPolicy database noting that the metric has been logged.
log_executable
This method will call into the ExecManagerService and call the logExecutable method. This eventually saves the information into the scan_targets_v2 table in the /var/db/SystemPolicyConfiguration/ExecPolicy database. These records gets used from periodic XPC activities to measure performance metrics.
com.apple.security.syspolicy.exec
This XPC service is defined in the syspolicyd launchd plist. Similar to the KextManager subsystem it’s an Objective-C XPC service. The NSXPCInterface is defined to implement the following interface:
There’s not much to this XPC service. It simply provides a way for clients to retrieve a list of 32-bit applications that have been executed. No special entitlements are needed to call into this service.
Clients
AppleSystemPolicy.kext
As far as I could tell this is the only client of the syspolicyd MIG service. Since syspolicyd provides this as a host special port the kernel extension does the following when it’s main IOService class is initialized:
The kernel extension then has it’s start method called which does the following:
The following are the MACF operations that get hooked:
- mpo_proc_notify_exec_complete
- mpo_file_check_library_validation
- mpo_file_check_mmap
All three of these hooks are simply used to inspect executables that are about to run or libraries that will be mapped into memory and check if they are 32-bit. If they are then a MIG call is made to inform syspolicyd of the information. If you want to see an example of what the MIG call itself looks like you can take a look at this small sample app I created called aspmig.c. It manually calls the notify_32bit_exec MIG service.
If you want to look at the statistics of how long the MACF hooks take to run you can use the sysctl command line utility.
SystemPolicy.framework
Similar to the KextManager subsystem. The SystemPolicy.framework is one of the main clients of the ExecManager service. You need to search for the SPExecutionPolicy class to find true clients of the XPC service. Doing that results in only a single client:
launchd
The launchd plist for syspolicyd is located at /System/Library/LaunchDaemons/com.apple.security.syspolicy.plist . In addition to all the services we already covered there are a handful of com.apple.xpc.activity entries in the plist. You can read more details about what XPC Activities are in the Energy Efficiency Guide for Mac Apps. I am a huge fan of XPC Activities. I think most 3rd party daemons do not make use of this functionality and if they would it would greatly improve their efficiency on the Mac. Taking this approach lets launchd make intelligent decision about when to launch certain background activities taking into account things like whether the device is on battery or not or if it can batch up certain requests to be more efficient. The list below just summarizes the ones defined and what they do but does not dive into them in any detail.
com.apple.security.syspolicy.report
This job runs once a day on an inexact schedule and never on battery. This gives launchd flexibility to batch up this job when the computer is on power and awake. The job makes use of the ExecutableMeasurementWorker class and runs the following query in the /var/db/SystemPolicyConfiguration/ExecPolicy database:
It then calls into the private WirelessDiagnostics.framework and calls AWDPostMetric to log the information.
com.apple.security.syspolicy.find.bundles
This job runs every 7 days as long as the machine isn’t on battery power. It calls into the BundleFinder class calling the searchKnownBundleLocations method. I didn’t look into this in detail but it looks like it attempts to find bundles on the system that it wants to scan and then adds the records into the scan_targets_v2 table in the /var/db/SystemPolicyConfiguration/ExecPolicy database.
com.apple.security.syspolicy.measure
This job runs every 3 days and isn’t allowed to run on battery. There’s not good documentation on all of launchd ’s keys but I would guess that the CPUIntensive flag is an indicator to launchd that this job might use a lot of CPU. The PowerNap key might indicate that the job can run while the machine is asleep during other PowerNap work periods. This job again makes use of the ExecutableMeasurementWorker class this time calling into the performMeasurementsWithCancelCheck method. This will in turn run the following sql query:
Based on the scan targets found it looks like the job will then attempt to call SecStaticCodeCreateWithPath to create a SecStaticCode object and pull out some information around the measured run time of the binary.
com.apple.security.syspolicy.kext.mt
This job runs every 6 days on an inexact schedule. It calls into the KextManagerPolicy class calling the logPolicyState method. This job will retrieve the current list of KEXTs from the /var/db/SystemPolicyConfiguration/KextPolicy database and then for each one attempt to locate it on the file system and eventually call into the SPMessageTracer class calling the logPolicyItem method. This in turn calls into the msgtracer_log_with_keys function which is provided by the libDiagnosticMessagesClient.dylib . Based on the name of this job and the initial KextManagerPolicy method called it seems to simply be logging the current state of approved KEXTs.
com.apple.security.syspolicy.rearm
This job runs once a day. Depending on whether Gatekeeper is enabled and some other internal checks in the Security.framework this job will re-enable Gatekeeper if it has been disabled.
Miscellaneous
Entitlements
When reviewing a system daemon I’m always interested to see what entitlements it has itself. In the case of syspolicyd it has the following entitlements.
Nothing really surprising here based on everything described above. It has entitlements that let it access and update the SIP restricted configuration databases for the various services as well as one related to MDM. I’m not sure what the com.apple.private.iokit.nvram-panicmedic but I think syspolicyd is the only binary on the system with this entitlement.
Defaults
A lot of system daemons make use of the macOS defaults system to store certain configuration options for itself. Below are the various defaults values I found while reviewing syspolicyd:
com.apple.security.syspolicy.KextPolicyForceEnable
This system default gets used in the KextManagerPolicyClass in the canLoadKernelExtensionAtURL:isCacheLoad: method. It checks if the value is set and seems to be a way to potentially force the KextManager subsystem on even if other things like SIP is disabled.
com.apple.security.syspolicy.ExecutableMeasurementDisable
Controls whether or not the com.apple.security.syspolicy.report XPC activity job runs.
com.apple.security.syspolicy.ExecutableMeasurementDisableFullValidation
Controls if full validation is done when performing a measurement.
com.apple.security.syspolicy.ExecutableMeasurementDisableCalculateFMJ
Whether code signing hash should be calculated during a measurement.
com.apple.security.GKAutoRearm
If the key is present and has a value of YES, Gatekeeper will turn itself on automatically if it’s disabled. If the key is present and has a value of NO, Gatekeeper settings will not change.
Revision History
What follows is a release history of syspolicyd pieced together from the previously open sourced security_systemkeychain code as well as looking through the closed source binary on different versions of macOS. Aside from macOS 10.7 I did not go through each minor OS revision only the most recent version of each major OS release. Where possible I’ve included links to the source code for each version.
Источник