Customized IOKit extension not work

Hi guys, How to achieve the following feature on macOS when a USB device (Camera/Mic/Speaker) is connected:

  1. When a third-party video conferencing app is not in a meeting, ensure the app defaults to using the USB device (Camera/Mic/Speaker).
  2. When a third-party conferencing app is in a meeting, ensure the app automatically switches to the USB device (Camera/Mic/Speaker).

I want to make use of IOKit extension to hidden or ignore build-in camera to realize the requirement. however the extension can't be loaded for Invalid permissions in MacOS 15.4.1, buildVersion:24E263. I also tried to run in in MacOS 14.4.1, which can be loaded but can't auto load when restart laptop as KDK version not match. Could you please give me some suggestion? Is it possible hidden build-in camera in MacOS M-series chip? Is there any other method to realize the feature. Thanks a lot.

Answered by DTS Engineer in 839753022

I want to make use of IOKit extension to hidden or ignore build-in camera to realize the requirement.

KEXT support has been formally deprecated and is no longer supported by Apple.

Could you please give me some suggestion? Is it possible hidden build-in camera in MacOS M-series chip?

The main issue here is that the built-in camera doesn't have a standard implementation, so the specific details vary considerable from model to model. Any solution to this is going to require significant testing across a very broad range of our products and will probably require active maintenance to support new devices and/or changes to the software stack used by those machines.

In any case, while I haven't looked into this in great details, I can think of three approaches that are likely to work:

  1. Use the EndpointSecurity framework to block access to the device. Routing video from the camera to user space is going to go the through a user client, so using ES_EVENT_TYPE_AUTH_IOKIT_OPEN to block that connection would prevent the camera from functioning.

  2. It might be possible to use a codeless DEXT to replace the existing KEXT. You can find a general description of that here and a more detailed example of that process here. Note that while this approach will function and might be useful for your own testing/experimentation, it is very unlikely that we would approve the necessary entitlements that would allow this to be distributed. In general, our policy has been that we grant DEXT entitlements to developers trying to suport "their" hardware, not to 3rd parties trying to interfere with other hardware.

  3. I'm not familiar enough with CoreMedia I/O to know what would be involved, but it's possible you might be able to use that framework to interfere with or "hide" our camera. Similarly, you might be able to simply claim exclusives access to the camera, which would prevent other clients from using it.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

The follow is my test program:

FakeISPFilter % tree . ├── FakeISPFilter │ ├── FakeISPFilter.cpp │ ├── FakeISPFilter.hpp │ ├── Info.plist │ └── main.cpp └── FakeISPFilter.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ └── swiftpm │ │ └── configuration │ └── xcuserdata │ └── lqs.xcuserdatad │ └── UserInterfaceState.xcuserstate └── xcuserdata └── lqs.xcuserdatad └── xcschemes └── xcschememanagement.plist

FakeISPFilter.hpp: #include <IOKit/IOService.h>

class FakeISPFilter : public IOService { OSDeclareDefaultStructors(FakeISPFilter) public: virtual bool start(IOService* provider) override; virtual void stop(IOService* provider) override; virtual IOService* probe(IOService* provider, SInt32* score) override; };

FakeISPFilter.cpp #include <IOKit/IOLib.h> #include "FakeISPFilter.hpp"

#define super IOService OSDefineMetaClassAndStructors(FakeISPFilter, IOService)

bool FakeISPFilter::start(IOService* provider) { IOLog("FakeISPFilter: ISP Camera filtered!\n"); // not call super::start(), so hidden build-in camera return true; }

void FakeISPFilter::stop(IOService* provider) { IOLog("FakeISPFilter: ISP Camera filter stopped.\n"); super::stop(provider); }

IOService* FakeISPFilter::probe(IOService* provider, SInt32* score) { IOLog("FakeISPFilter: probe called!\n"); if (score) *score = 100000; // use the higher priority to replace build-in camera driver return this; }

main.cpp #include <IOKit/IOLib.h>

======================================== Info.plist <?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>CFBundleIdentifier</key> <string>com.lqs.MyVirtualCam.FakeISPFilter</string> <key>CFBundleExecutable</key> <string>FakeISPFilter</string> <key>IOKitPersonalities</key> <dict> <key>FakeISPFilter</key> <dict> <key>CFBundleIdentifier</key> <string>com.lqs.MyVirtualCam.FakeISPFilter</string> <key>IOProviderClass</key> <string>AppleARMIODevice</string> <key>IONameMatch</key> <string>isp,t8101</string> <key>IOClass</key> <string>FakeISPFilter</string> </dict> </dict> <key>OSBundleLibraries</key> <dict> <key>com.apple.kpi.libkern</key> <string>8.0.0</string> <key>com.apple.kpi.iokit</key> <string>8.0.0</string> </dict> </dict> </plist>

I want to make use of IOKit extension to hidden or ignore build-in camera to realize the requirement.

KEXT support has been formally deprecated and is no longer supported by Apple.

Could you please give me some suggestion? Is it possible hidden build-in camera in MacOS M-series chip?

The main issue here is that the built-in camera doesn't have a standard implementation, so the specific details vary considerable from model to model. Any solution to this is going to require significant testing across a very broad range of our products and will probably require active maintenance to support new devices and/or changes to the software stack used by those machines.

In any case, while I haven't looked into this in great details, I can think of three approaches that are likely to work:

  1. Use the EndpointSecurity framework to block access to the device. Routing video from the camera to user space is going to go the through a user client, so using ES_EVENT_TYPE_AUTH_IOKIT_OPEN to block that connection would prevent the camera from functioning.

  2. It might be possible to use a codeless DEXT to replace the existing KEXT. You can find a general description of that here and a more detailed example of that process here. Note that while this approach will function and might be useful for your own testing/experimentation, it is very unlikely that we would approve the necessary entitlements that would allow this to be distributed. In general, our policy has been that we grant DEXT entitlements to developers trying to suport "their" hardware, not to 3rd parties trying to interfere with other hardware.

  3. I'm not familiar enough with CoreMedia I/O to know what would be involved, but it's possible you might be able to use that framework to interfere with or "hide" our camera. Similarly, you might be able to simply claim exclusives access to the camera, which would prevent other clients from using it.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

hi apples, I want to know whether it’s permitted by apple’s privacy to realize the following two requirements:

  1. When a third-party video conferencing app is not in a meeting, ensure the app defaults to using the USB device (Camera/Mic/Speaker).
  2. When a third-party conferencing app is in a meeting, ensure the app automatically switches to the USB device (Camera/Mic/Speaker).

Hello Kevin, According to your suggestion 1, I can disable build-in camera before a third party app opens it, however I can’t disable it after the camera is opened, so the camera can be used on the situation, which can‘t satisfy my requirement. do you have any other suggestion? thanks.

ES clients are generally built as LaunchDaemons and the API includes a specific option that ensure the ES client is launched during early boot, before ANY other 3rd party (non-apple signed) code is allowed to execute. That allows an ES client to ensure that an attacker cannot get "infront" of it and that's particularly true of something relatively "high level" like camera access.

As a side note here, I'm not sure what you're larger concern/requirement here is but the ES client is the only approach in that list that is truly "secure", as an ES client can harden itself against tampering to extent that no other component can.

How can I get some samples of using CoreMedia I/O to realize "hide" build-in camera?

Having looked into this further and given your concerns about race conditions with other clients, I don't believe this approach is viable.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Hello Kevein, Thanks for your reply.

Multiline ES clients are generally built as LaunchDaemons and the API includes a specific option that ensure the ES client is launched during early boot, before ANY other 3rd party (non-apple signed) code is allowed to execute. That allows an ES client to ensure that an attacker cannot get "infront" of it and that's particularly true of something relatively "high level" like camera access.

Yes, I got it. Maybe I didn't introduce the case clearly. The case is that before I run the ES extension, the 3rd party video meeting app has opened the build-in camera and using it. At this moment, I start the extension and it can't block the app access the cam because ES_EVENT_TYPE_AUTH_IOKIT_OPEN only controls the 3rd app open the camera, but not has opened it.

Multiline Having looked into this further and given your concerns about race conditions with other clients, I don't believe this approach is viable.

Got it, so it's impossible to "hide" the build-in camera and let the 3rd party apps switch to my usb camera automatically by CMIO, is it right?

Yes, I got it. Maybe I didn't introduce the case clearly. The case is that before I run the ES extension, the 3rd party video meeting app has opened the build-in camera and using it. At this moment, I start the extension and it can't block the app access the cam because ES_EVENT_TYPE_AUTH_IOKIT_OPEN only controls the 3rd app open the camera, but not has opened it.

Yes, I understood that. What I was pointing out here is that the ES API is designed so that, once an ES client installed, it is IMPOSSIBLE for anything to run "before" it. In other words, once you'd installed and activated your ES client the problem you're describing simply cannot happen.

Got it, so it's impossible to "hide" the build-in camera and let the 3rd party apps switch to my usb camera automatically by CMIO, is it right?

Correct, CMIO won't help with this. You could write an app that opened the built in camera "itself" to block access, however, that has exactly the same race condition you were concerned about the ES client having.

I think the right solution here really depends on what the product you're trying to build is actually "for". That is:

  • If you're trying to create a simple utility app that as user could run to "encourage" using external camera access, then an app that simply open the built in camera and keeps it that way would work fine. It's trivial to bypass (just open meeting app "first"), but that doesn't matter as you're assuming the user is directly managing this process anyway.

  • If you're actually trying to PREVENT built-in camera access in a truly reliable/secure way, then an ES client is the answer, as it's the only approach that can't be trivially bypassed.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Updating the information here, starting in macOS 26, ES_EVENT_TYPE_AUTH_IOKIT_OPEN has been made significantly more useful/capable. See my forum post here for more detail.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Customized IOKit extension not work
 
 
Q