Search code examples
macosdarwinmach

Where are mach_msg helpers for kernel functions implemented or generated?


Communication with mach kernel functions happens using mach messages. The libsystem_kernel.dylib system library implements a mach_msg(...) helper function to send/receive arbitrary mach messages, but it also contains prepared methods to use certain kernel functions like task_get_special_port (which go by the same function name). This can be seen by disassembling the lib binary.

The mach_msg source can be found here but the sources for the function-specific helpers like task_get_special_port doesn't seem to appear anywhere in the libsyscall source tree. Where are those kernelFunction-to-machMsg-adapters implemented or generated?

Also where is the receiver of the mach message implemented which translates between the message and the kernel function call? (The actual kernel implementation for task_get_special_port can be found here)


Solution

  • Where are those kernelFunction-to-machMsg-adapters implemented or generated?

    They are generated by the Mach Interface Generator (MIG). If you look in the kernel sources for files with the extension .defs, you can see the definitions used for generation by MIG.

    Stated in the Apple Docs:

    At the trap level, the interface to most Mach abstractions consists of messages sent to and from kernel ports representing those objects. The trap-level interfaces (such as mach_msg_overwrite_trap) and message formats are themselves abstracted in normal usage by the Mach Interface Generator (MIG). MIG is used to compile procedural interfaces to the message-based APIs, based on descriptions of those APIs.

    For task_get_special_port, you can see the defs file here.

    If you call mig on that file, it will generate three files.

    • A .c file for the sender (taskUser.c)
    • A .c file for the receiver (taskServer.c)
    • A header file that defines the protocol for communication between the sender and receiver (task.h)

    Examining the Server.c file, you can see this function, with the direct call to task_get_special_port.

    mig_internal novalue _Xtask_get_special_port
            (mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)
    {
        ...
    
            RetCode = task_get_special_port(In0P->Head.msgh_request_port, In0P->which_port, &OutP->special_port.name);
            if (RetCode != KERN_SUCCESS) {
                    MIG_RETURN_ERROR(OutP, RetCode);
            }
    
        ...
    }
    

    Using mig is much less error prone than having to manually write the client and server protocols.