core audio user-space plug-in driver - sandbox preventing data interaction from another process
Asked Answered
E

1

10

I'm working on a coreaudio user-space hal plugin based on the example developer.apple.com/library/mac/samplecode/AudioDriverExamples/Introduction/Intro.html

In the plug-in implementation, I plan to obtain audio data from another process i.e. CFMessagePort

However, I got the following error in console trying to create port CFMessagePortCreateLocal...

sandboxd[251]: ([2597]) coreaudiod(2597) deny mach-register com.mycompnay.audio

I did some googlging and came to this article

Technical Q&A QA1811 https://developer.apple.com/library/mac/qa/qa1811/_index.html about adding AudioServerPlugIn_MachServices in plist but still no success.

Is there anything else I need to do to make this work (like adding entitlements, code-sign) or this is not the correct approach.? I am not sure if MesssagePort mechanism works anymore under sandbox. would XPC Services be viable?

Thank you very much for your time. Any help is greatly appreciated


update 1:

I should be creating a remote port instead of a local in the audio plug-in. Having that said, with the AudioServerPlugIn_MachServices attribute in the plist. now there is no sandboxd[559]: ([552]) coreaudiod(552) deny mach-lookup / register message in console.

However, in my audio hal plug-in (client side) I have

CFStringRef port_name = CFSTR("com.mycompany.audio.XPCService"); CFMessagePortRef port = CFMessagePortCreateRemote(kCFAllocatorDefault, port_name); port has return the value of 0. I tried this in a different app and it works just fine.

This is my server side:

CFStringRef port_name = CFSTR("com.mycompany.audio.XPCService");
CFMessagePortRef  port = CFMessagePortCreateLocal(kCFAllocatorDefault, port_name, &callback, NULL, NULL);
CFRunLoopSourceRef runLoopSource =
CFMessagePortCreateRunLoopSource(nil, port, 0);

CFRunLoopAddSource(CFRunLoopGetCurrent(),
                   runLoopSource,
                   kCFRunLoopCommonModes);
CFRunLoopRun();

I did get a console message regarding this.

com.apple.audio.DriverHelper[1314]: The plug-in named SimpleAudioPlugIn.driver requires extending the sandbox for the mach service named com.mycompnay.audio.XPCService

anyone know why??


update 2

I noticed that when I use the debug mode with coreaudiod it does successful get the object reference of the mach service. (same thing happened when I was trying the xpc_service approach) project scheme setting

Anyone??

Evanevander answered 15/10, 2015 at 1:21 Comment(4)
Hi Allen, just trying to setup debugging this. First of all, how did you manage to debug using coreaudiod at all ? I get "error: attach failed: lost connection" all the time...Whereby
@Whereby I got my info here: Debugging a user-space HAL plugin? and Debugging an AudioServer pluginEvanevander
Thanks @Allen, I finally got it to work by setting "csrutil disable" in Recovery OS mode, so that debugging coreaudiod got possible! :)Whereby
#41017058Laurellaurella
C
7

I'm pretty sure I was running into the same problems in my AudioServerPlugIn. I could look up and use every Mach service I tried, except for the ones I had created. And the ones I had created worked normally from a regular process.

Eventually I read the Daemonomicon and figured out that coreaudiod (which hosts the HAL plugins) was using the global bootstrap namespace, but my service was being registered in the per-user bootstrap namespace. And since "processes using the global namespace can only see services in the global namespace" my plugin couldn't see my service.

You can use launchctl to test this by having it run the program that registers your service, but with the same bootstrap namespace as coreaudiod. You'll probably need to have rootless disabled.

# launchctl bsexec $(pgrep coreaudiod) your_service_executable

With that running, try to connect from your plugin again.

From Table 2 in the Daemonomicon, you can see that only launchd daemons use the global bootstrap namespace. That explains why coreaudiod uses it. And I think it means that your Mach service needs to be created by a launchd daemon.

To make one, create a launchd.plist for your service in /Library/LaunchDaemons. Set its owner to root:wheel and make it only writable by the owner. In it, set the MachServices key and add the name of your service:

<key>MachServices</key>
<dict>
    <key>com.mycompany.audio.XPCService</key>
    <true/>
</dict>

Then register it:

# launchctl bootstrap system /Library/LaunchDaemons/com.mycompany.audio.XPCService.plist

This is what I ended up with: com.bearisdriving.BGM.XPCHelper.plist.template. Note that without the UserName/GroupName keys your daemon will run as root. (The code for my service and plugin is in that repo as well, in case that's helpful.)

I ended up having to use XPC, unfortunately, but I tried CFMessagePort first and it worked fine.

It also seems to all work fine whether the plugin is signed or not. Though, as you say, you do need the AudioServerPlugIn_MachServices key in your Info.plist.

Caudex answered 15/4, 2016 at 13:5 Comment(5)
Thank you @Caudex for replying in a very descriptive way. I was able to make the XPC communicate in a slightly different approach than the one you suggested here (not sure if it's the appropriate way). I created my C-based xpc functions in a int main(int argc, const char * argv[]) intermediary process. Did sudo chown root with my plist in /LaunchDaemons. I'm going to spend some time going over your example. Really appreciate your answer. by the way, that CFMessagePort never worked for me. would've been great if it did.Evanevander
I still can't seem to get this working (a year later). I've combed over Background Music and this answer several times and I'm still seeing the dreaded requires extending the sandbox for the mach service error and no connection. Permissions seem right, ownership seems right, launchd is verified to be working on the XPC service and it's bootstrapped using launchctl bootstrap system /System/LaunchDaemons/my.service.plist to no avil. :| I'm at wits end.Labe
Why did to end up having to use XPC instead of CFMessagePort?Breland
@RuurdAdema Not sure, sorry. I actually reread this answer recently and asked myself the same question. The main thing I'm using XPC for is to block in StartIO until another process tells my plug-in it can start IO, so my guess is that I wasn't able to receive the reply from the CFMessagePort until after I let StartIO return. That said, just from the docs, I don't see why I wouldn't have been able to receive the reply on a different thread.Caudex
CFMessagePort won't work with Catalina, I'm struggling on getting XPC workingIntuit

© 2022 - 2024 — McMap. All rights reserved.