Mac OS X,  Mac Security,  Swift

Removing Extensions Cruft from macOS

Extensions have gotten a pretty substantial overhaul over the past few years. Traditionally, a kernel extension (or kext for short) would usually be located in /Library/Extensions or /System/Library/Extensions and have a file extension (no pun intended) of .kext. Apple began to move away from Kernel Extensions and towards more purpose-built extensions, which included System Extensions, located at /Library/SystemExtensions. Apple also introduced a number of new extension types that reside in application bundles. An app can load the extension and developers get those features “for free” rather than writing their own code to do what they once had to do with Kernel Extensions.

To remove Extensions, Apple has introduced the Extensions System Setting, available by opening System Settings, the settings for Privacy & Security, and then Extensions.

As applications attempt to access libraries that developers import from those extensions, the Mac will prompt to provide access to them. If access is granted the box is checked for each. Some work a little differently, like the Password AutoFill Extension. Access to load that Extension needs to be granted explicitly.

In the above example, a CredentialProvider extension was created, which allows (for example) Safari to list a second password manager (in addition to Keychain). The project in Apple’s App Store Connect doesn’t show the Extensions included but they can be seen by going to the Developer Portal and clicking on the app’s entry in “Certificates, Identifiers & Profiles”. Each checkbox can have a different behavior according to how developers at Apple deem it appropriate to protect the privacy of users of Apple devices.

The bundle id in the above screen should match a code sign check of a given app. For example, using -dr to check MyAwesomeApp.app:

codesign -dr - /Applications/MyAwesomeApp.app

To remove Extensions, the main idea is that since the Extension is loaded dynamically by the app on launch, simply delete the app. It can then be re-installed. Apps get to be smaller and have sometimes tiny footprints when it comes to system resources consumed because the Apple-provided Extensions can do a lot of the work. Since artifacts can dynamically load when the app is running they might leave cruft behind in a few places once the application is removed. The earlier CredentialProvider extension might appear three times. A common spot for developers that can cause duplicate extensions to load is ~/Library/Developer/Xcode/DerivedData. An app, especially if renamed or there’s an iOS and Mac version, can leave additional application bundles when developers go to build and/or run apps. Even though those bundles aren’t in /Applications they were opened once and the OS has a looooong memory. Removing duplicate apps in there (I prefer to do it one-by-one) and restarting can clear those out. Personally, I also remove the app itself and re-install for good measure.

Artifacts can also show up in the following locations, including in some cases swift code that substantiate an object or a preference that can change a behavior:

  • /Library/Application Support/
  • ~/Library/Application Support/
  • ~/Library/Preferences/
  • ~/Library/Containers/
  • ~/Library/Group Containers/

These are all directories, so to empty them use (replacing bundleid or name of the app with “bundleid” in the below command:

rm -rf ~/Library/Containers/bundleid

Further, cruft can be passed to Keychain or iCloud Keychain and then get sync’d to other devices. This is all just handled for tvOS and iOS because of how those really only have one way to remove apps. But we can remove bits of apps or components in macOS. For System Extensions, it’s also possible to reset extensions. To see if there are any System Extensions running, use systemextensionsctl:

systemextensionsctl list

The reset verb can be used to reset a bundleID, or they can be uninstalled using the uninstall verb.

The kextcache, kextfind, kextlibs, kextload, kextstat, kextunload, and kextutil commands can still be used to interact with kexts; however given that these types of extensions are being deprecated their usefulness is less and less with each passing year.

Ultimately, the new Extensions types work better, cause less interference with other apps/tools, and provide more telemetry to users in regards to what are on their devices. They are newer and so less mature in how they operate. They don’t all follow the same standards for activation and inclusion. In some cases, the buttons to make them work are in kinda’ wonky places in the Developer Portal, or if there’s Mac and iOS versions of an app we have to make app groups. However, the price developers need to pay is worth it, since it’s mostly just button mashing like an old version of Myst where we have to solve an arcane riddle. The end user benefits while developers await consistency. However, for systems administrators, especially those who have to troubleshoot developer machines for code that uses Extensions, it can be a bit of work. And this hasn’t even touched on privacy controls (e.g. via tccutil), identities (e.g. via “Log in with Apple”, or centralized management of any of this via Mobile Device Management.