3 Replies
      Latest reply on Jun 26, 2019 12:35 AM by eskimo
      BoilerLA Level 1 Level 1 (0 points)

        We have a daemon that is launched by launchd, always running in the background and running as root. The daemon is installed to /Library/LaunchDaemons.

         

        To reduce its attack surface we want to move some functionality into another helper process. It doesn't have to be running as root, but since the client (the LaunchDaemon) is running as root and in the launchd context, we created another LaunchDaemon that is launched on-demand and uses the MachService key to advertise its Mach service. It is also installed to /Library/LaunchDaemons.

         

        The sandboxed daemon has little functionality in it, and its entitlements are just com.apple.security.app-sandbox. We use NSXPC to communicate between the the non-sandboxed daemon and the sandboxed daemon. The sandboxed helper daemon launches as expected.

         

        However the sandboxed application exits immediately on 10.14 with the following crash:

         

        Crashed Thread:        0  Dispatch queue: com.apple.main-thread
        
        
        Exception Type:        EXC_BAD_INSTRUCTION (SIGILL)
        Exception Codes:       0x0000000000000001, 0x0000000000000000
        Exception Note:        EXC_CORPSE_NOTIFY
        
        
        Termination Signal:    Illegal instruction: 4
        Termination Reason:    Namespace SIGNAL, Code 0x4
        Terminating Process:   exc handler [1721]
        
        
        External Modification Warnings:
        Debugger attached to process.
        
        
        Application Specific Information:
        dyld: launch, running initializers
        /usr/lib/libSystem.B.dylib
        Sandbox registration internal error: Incoming message euid:1 does not match secinitd uid:0.
        
        
        Application Specific Signatures:
        Internal error: Incoming message euid:1 does not match secinitd uid:0.
        
        
        Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
        0   libsystem_secinit.dylib        0x00007fff5b6e6b2a _libsecinit_setup_secinitd_client + 1929
        1   libsystem_secinit.dylib        0x00007fff5b6e6340 _libsecinit_initialize_once + 13
        2   libdispatch.dylib              0x00007fff5b49e63d _dispatch_client_callout + 8
        3   libdispatch.dylib              0x00007fff5b49fd4c _dispatch_once_callout + 20
        4   libsystem_secinit.dylib        0x00007fff5b6e6331 _libsecinit_initializer + 79
        5   libSystem.B.dylib              0x00007fff582b09d4 libSystem_initializer + 136
        6   dyld                          0x0000000108408592 ImageLoaderMachO::doModInitFunctions(ImageLoader::LinkContext const&) + 506
        
        
        

         

        If we remove the entielements from the sandboxed helper, thus making it non-sandboxed, it works fine but this is obviously not the intent.

         

        Any ideas?

        • Re: XPC between sandboxed launchd helper and non-sandboxed daemon
          eskimo Apple Staff Apple Staff (12,335 points)

          The App Sandbox is… well… an app sandbox.  It’s designed for user programs (app, app extensions, XPC Services) not for daemons.  You may be able to get it to work in that context, but it’s not a well-trodden path (most Apple daemons use their own custom sandbox profile).

          Internal error: Incoming message euid:1 does not match secinitd uid:0.

          This message is generated by the secinitd (see its man page) when an App Sandbox client’s UID doesn’t match the session for which that instance of secinitd was started.

          It doesn't have to be running as root, but since the client (the LaunchDaemon) is running as root and in the launchd context, we created another LaunchDaemon that is launched on-demand and uses the MachService key to advertise its Mach service.

          What UID does this helper run as?  The error message you’re seeing indicates that you’ve configured the helper to run as the daemon user (UID 1)?

          Share and Enjoy

          Quinn “The Eskimo!”
          Apple Developer Relations, Developer Technical Support, Core OS/Hardware
          let myEmail = "eskimo" + "1" + "@apple.com"

            • Re: XPC between sandboxed launchd helper and non-sandboxed daemon
              BoilerLA Level 1 Level 1 (0 points)

              Unfortunately the `sandbox_init` family of APIs are deprecated, otherwise I'd have take that route.

               

              What UID does this helper run as?  The error message you’re seeing indicates that you’ve configured the helper to run as the daemonuser (UID 1)?

              The helper does not set any specific UID in its LaunchDaemon.plist, and on the filesystem it's owned by root:admin, so presumably it is spawned as root. Maybe xpcproxy is UID 1?

               

              Not necessarily what we want, but since its parent is root and launched by launchd, it needs to be able to lookup the Mach service for the helper so making the helper a LaunchDaemon was easiest. Making it a LaunchAgent would make it very hard for it to be launched on-demand by the root LaunchDaemon.

                • Re: XPC between sandboxed launchd helper and non-sandboxed daemon
                  eskimo Apple Staff Apple Staff (12,335 points)

                  Unfortunately the sandbox_init family of APIs are deprecated, otherwise I'd have take that route.

                  Even if they weren’t, it wouldn’t help you because the format of the file you pass in has never been documented for third-party use )-:

                  Making it a LaunchAgent would make it very hard for it to be launched on-demand by the root LaunchDaemon.

                  Right.  And that’s not the only problem.  Another issue is that an agent has to run in a per-user session of some form, and there can be multiple sessions active at a time, making it hard for the daemon to know what session to target.

                  It also introduces the possibility of a security inversion, where the user who owns the session can affect the behaviour of the daemon indirectly, by fiddling with the agent.

                  The helper does not set any specific UID in its LaunchDaemon.plist, and on the filesystem it’s owned by root:admin, so presumably it is spawned as root.

                  OK.

                  Maybe xpcproxy is UID 1?

                  I don’t think so.  Hmmm, that’s a bit of a mystery really.

                  Regardless, I don’t think this is a viable path.  As I mentioned earlier, the App Sandbox just wasn’t designed for daemons.  Moreover, if you run your helper as root, you’re extended a bunch of privileges to it than significantly undermine any extra security you might get from sandboxing it.

                  Share and Enjoy

                  Quinn “The Eskimo!”
                  Apple Developer Relations, Developer Technical Support, Core OS/Hardware
                  let myEmail = "eskimo" + "1" + "@apple.com"