Sharing Mach ports with child processes
Asked Answered
F

3

9

I am doing a comparison of different IPC mechanisms available on Mac OS X (pipes, sockets, System V IPC, etc.), and I would like to see how Mach ports compare to the higher-level alternatives. However, I've run into a very basic issue: getting send rights to ports across processes (specifically, across a parent process and a child process).

Unlike file descriptors, ports are generally not carried over to forked processes. This means that some other way to transfer them must be established. Just about the only relevant page I could find about this was this one, and they state in an update that their method no longer works and never was guaranteed to, even though that method was suggested by an Apple engineer in 2009. (It implied replacing the bootstrap port, and now doing that breaks XPC.) The replacement they suggest uses deprecated functions, so that's not a very appealing solution.

Besides, one thing I liked about the old solution is that ports remained pretty much private between the processes that used it. There was no need to broadcast the existence of the port, just like pipes (from the pipe call) work once forked. (I'll probably live with it if there's another solution, but it's a little annoying.)

So, how do you pass a send right to a Mach port from a parent process to a child process?

Fluxmeter answered 30/3, 2013 at 20:42 Comment(0)
G
4

bootstrap_register is deprecated but bootstrap_check_in isn't, and can be used to register your port which can later be retrieved by the child process by using bootstrap_look_up. (This still doesn't provide the privacy you're looking for, unfortunately).

Gastrocnemius answered 4/12, 2013 at 18:12 Comment(3)
What do you mean by "isn't secure"?Grosbeak
In reference to OP: "one thing I liked about the old solution is that ports remained pretty much private between the processes that used it. There was no need to broadcast the existence of the port"Gastrocnemius
Ahhh, I see... well "private" and "secure" are quite different meanings in pretty much every aspect, so I didn't get that you were referring to this statement. Thanks for clarification.Grosbeak
G
1

The recommended solution is to not use Mach IPC directly at all but implementing your child process as an XPC service, in which case you can use the XPC API that will use Mach IPC behind the scene, yet you don't have to deal with any details. You have an easy API to send XPC messages in the parent and an easy API to receive XPC messages in the client, that can also pass back replies easily. The system will handle all the hard parts for you.

https://developer.apple.com/library/mac/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingXPCServices.html

If you cannot use the XPC API, keep in mind that when you register your service with bootstrap_check_in() (which is not deprecated), it won't be private, but if you do so in a user space process, it will be private to your login session: root processes won't see it, processes of other users neither. If you do that in a root process, it will be visible to all sessions, though.

Also note however, that you can control who may send you IPC messages and who not. You can request a mach_msg_audit_trailer_t when receiving a mach message. That way you get access to the audit_token_t of the sender. And using audit_token_to_pid() you can get the pid_t of the sender. As you know the PID of your child, you can simply ignore all messages (passing it to mach_msg_destroy() to avoid leaking resources), unless the message was sent by your child process. So you cannot avoid your port to be discover-able, but you can avoid that any process other than your child process may use this port.

And last not but not least, you can just give your port a random name, after all only your child process needs to know it, so you can dynamicall generate a name in the parent process and the pass it along to your child process, that way your port can be seen if software scans for ports but most software just uses hardcoded names anyway.

Grosbeak answered 4/9, 2016 at 14:0 Comment(0)
D
0

One thing you might try (although it's a gross hack) is hijacking the exception ports as an inheritance mechanism. Set a custom port as an exception port in the parent, fork the child, have the child get the custom port from its exception port, send its task port to the parent, the parent resets its exception port, resets the child's exception port, and then the two proceed from there with a communication channel. See task_set_exception_ports().

Dearborn answered 31/3, 2013 at 18:17 Comment(1)
Yeah, that was a "decent" hack with the bootstrap port, but I'd rather not do it with any other special port.Fluxmeter

© 2022 - 2024 — McMap. All rights reserved.