核心音频用户空间插件驱动程序 - 沙盒防止来自另一个进程的数据交互

10

我正在开发基于示例developer.apple.com/library/mac/samplecode/AudioDriverExamples/Introduction/Intro.html的coreaudio用户空间hal插件。

在插件实现中,我计划从其他进程(即CFMessagePort)获取音频数据。

然而,在尝试创建端口CFMessagePortCreateLocal时,在控制台中得到以下错误:

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

我进行了一些搜索,并阅读了这篇文章:

Technical Q&A QA1811 https://developer.apple.com/library/mac/qa/qa1811/_index.html,讲解了在plist中添加AudioServerPlugIn_MachServices,但仍无法成功。

除了添加权限、代码签名外,是否还需要做其他事情才能使其正常工作? 我不确定MesssagePort机制是否仍可用于沙箱中。XPC服务是否可行?

非常感谢您的时间。任何帮助都将不胜感激。


更新1:

在音频插件中,我应该创建一个远程端口而不是本地端口。因此,在plist文件中使用AudioServerPlugIn_MachServices属性后,现在控制台中没有sandboxd[559]: ([552]) coreaudiod(552) deny mach-lookup / register消息。

然而,在我的音频hal插件(客户端)中,我有以下代码:

CFStringRef port_name = CFSTR("com.mycompany.audio.XPCService"); CFMessagePortRef port = CFMessagePortCreateRemote(kCFAllocatorDefault, port_name); 端口返回0。我在另一个应用程序中尝试了这个方法,并且可以正常工作。

以下是我的服务器端:

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();

我确实收到了有关此事的控制台消息。

com.apple.audio.DriverHelper[1314]: 名为SimpleAudioPlugIn.driver的插件需要扩展沙盒以使用名为com.mycompnay.audio.XPCService的mach服务

有人知道为什么吗??


更新2

我注意到当我使用coreaudiod的调试模式时,它成功获取了mach服务的对象引用。(当我尝试使用xpc_service方法时也发生了同样的事情) 项目方案设置

有人知道吗?


嗨,艾伦,我正在尝试设置调试。首先,你是如何成功使用coreaudiod进行调试的?我总是收到“错误:附加失败:连接丢失”的提示... - Robert
1
@Robert 我在这里获取了我的信息:调试用户空间HAL插件?调试AudioServer插件 - Allen
1
谢谢@Allen,我终于通过在恢复OS模式下设置“csrutil disable”来使调试coreaudiod成为可能! :) - Robert
https://dev59.com/2J3ha4cB1Zd3GeqPPyZg - pkamb
1个回答

7

我很确定我在我的AudioServerPlugIn中遇到了相同的问题。我可以查找和使用我尝试过的每个Mach服务,除了我创建的那些。而我创建的那些在常规进程中正常工作。

最终我读了Daemonomicon并发现coreaudiod(托管HAL插件)正在使用全局引导命名空间,但我的服务正在注册到每个用户的引导命名空间中。由于"使用全局命名空间的进程只能看到全局命名空间中的服务",我的插件无法看到我的服务。

您可以使用launchctl来测试这一点,让它以与coreaudiod相同的引导命名空间运行注册服务的程序。您可能需要禁用rootless。

# launchctl bsexec $(pgrep coreaudiod) your_service_executable

运行后,请尝试从插件再次连接。

从《Daemonomicon》的表2中,您可以看到只有launchd守护程序使用全局引导命名空间,这解释了为什么coreaudiod会使用它。我认为这意味着您的Mach服务需要由一个launchd守护程序创建。

要创建一个launchd守护程序,请在/Library/LaunchDaemons中为您的服务创建一个launchd.plist。将其所有者设置为root:wheel,并仅允许所有者写入。在其中,设置MachServices键并添加您的服务名称:

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

然后注册它:
# launchctl bootstrap system /Library/LaunchDaemons/com.mycompany.audio.XPCService.plist

这是我最终得到的结果:com.bearisdriving.BGM.XPCHelper.plist.template。请注意,如果没有UserName/GroupName键,您的守护程序将以root身份运行。(我的服务插件的代码也在该存储库中,如果有帮助的话。)
不幸的是,我最终不得不使用XPC,但我先尝试了CFMessagePort并且它能正常工作。
无论插件是否已签名,似乎一切都正常工作。但是,正如您所说,您需要在Info.plist中添加AudioServerPlugIn_MachServices键。

1
感谢@freshtop详细回复。我能够以稍微不同的方式使XPC通信,而不是您在此处建议的方式(不确定是否是适当的方式)。我在**int main(int argc, const char * argv[])**中间进程中创建了基于C的xpc函数。使用sudo chown root和我的plist在/LaunchDaemons中。我将花一些时间研究您的示例。非常感谢您的答案。顺便说一句,那个CFMessagePort对我从来没有起作用过。如果它能起作用就太好了。 - Allen
1
一年后,我似乎仍然无法让它工作。 我已经仔细研究了"Background Music"和这个答案多次,但仍然看到可怕的“需要扩展沙盒以获取mach服务”的错误和连接失败。权限似乎正确,所有权也正确,XPC服务上的launchd已经验证过并且使用launchctl bootstrap system /System/LaunchDaemons/my.service.plist引导,但仍然没有用。我已经束手无策了。 - Qix - MONICA WAS MISTREATED
1
为什么最终不得不使用XPC而不是CFMessagePort? - Ruurd Adema
1
@RuurdAdema 不确定,抱歉。最近我重新阅读了这个答案,并问自己同样的问题。我使用XPC的主要目的是在StartIO中阻塞,直到另一个进程告诉我的插件它可以开始IO,所以我猜测我无法在让StartIO返回之前收到来自CFMessagePort的回复。话虽如此,仅从文档上看,我不明白为什么我不能在不同的线程上接收回复。 - freshtop
CFMessagePort在Catalina上无法工作,我正在努力让XPC工作。 - Steven

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接