MandatoryAccessControl (MAC) Framework
, the idea of Sandbox was definitely not bad, but nowhere near successful. The MACF framework is pretty much the foundation on top of which the entire security model of the Apple devices is built.com.apple.security.app-sandbox
. If the application has this entitlement, it will be placed in a container regardless of the wish of the developer. To be frank, developer’s opinion is kinda moot anyway, because applications uploaded into the macOS App Store are signed by Apple and during the signing process, Apple graciously slaps the Sandbox entitlement on the application thus forcing the containerization of any App Store application./var/mobile/Containers
and /var/Containers
. These paths have changed a lot beginning with iOS 8 when new folders were created and things were moved around to separate App resources, static from runtime data, so on older iOS, you may find the apps installed in /var/mobile/Applications
or even /var/mobile/Containers/Bundle/
. It doesn’t matter. Anything in /var/
is destined to be Sandboxed and there is no way around it because you cannot just install your app elsewhere, unless you Jailbreak the device, of course. On macOS, only App Store apps are guaranteed to be sandboxed. If you get an application in a DMG image from a developer website (which is extremely common), it is very likely not sandboxed.System32
folder or other important files. Why? Because there is no Sandbox in place on Windows. Yes, some resources need the user to confirm they want to open a program in “Administrator mode”, thus elevating the privileges, but it has become second nature to many people to just press “Run”, so it won’t protect much.userland daemon
located in /usr/libexec/sandboxd
, there is the com.apple.security.sandbox
which is a kext (Kernel Extension)
, and there’s also the AppSandbox
private framework which relies on AppContainer.Framework
. As you can see, multiple components work together to implement what we call the App Sandbox
.kextstat | grep 'sand'
command in Terminal.MACF Policy modules
. The CodeSign
enforced by AMFI (Apple Mobile File Integrity)
is another module.com.apple.security.app-sandbox
entitlement in the application binary. We can check the entitlements on macOS using multiple tools, but my favorite is jtool
by Jonathan Levin. By running the command ./jtool --ent /Applications/AppName.app
in Terminal, we can see the full list of entitlements that the application possesses. Let’s try it with iHex, an app I got from the macOS App Store, and then with OpenBoardView - an app downloaded in DMG format.true
. This application will be Sandboxed. Now, as you could see, these entitlements are listed in a format akin to XML. That is because they’re actually in a .PLIST or Property List
file which is nothing but a glorified XML. PLISTs can, however, come in binary format, but one can easily convert them in the human-readable format by using the command plutil -convert xml1 -o
.Jtool
, one can easily replace the entitlements of the application but that requires fake-signing the app. All in all, this is a method to unsandbox a macOS application. This cannot be easily done on iOS because the sandboxing there is based on the location where the app is installed and not solely on the possession of an entitlement.jtool
, but the point is, yes, non-App Store apps are, indeed, more dangerous.com.apple.security.app-sandbox
entitlement was not added by the developer of the iHEX application, it was added automatically by Apple in the process of signing when the application got published in the App Store and there is nothing the developer could do to remove the entitlement, other than distributing their app via other means. Normally the entitlements tell what your application CAN do. In the case of this entitlement, it pretty much limits the application heavily from accessing system resources or user data.asctl sandbox check --pid XYZ
where XYZ is the PID (Process ID)
of the application you’re interested in. You can get the PID
of a running process from the Activity Monitor
application on macOS. Here’s the output of the asctl
command.$HOME/Library/Containers/
. This folder is created for any sandboxed application regardless of the place the actual binary is installed on. The folder follow a simple structure, but most importantly, it contains a Container.Plist
file which contains information about the application whose Container this is (identified by its CFBundleIdentifier
), the SandboxProfileData
, the SandboxProfileDataValidationInfo
and the Version
of the Sandbox.ls -lF com.hewbo.hexeditor
. Where com.hewbo.hexeditor
is the CFBundleIndentifier
of the iHex app (you can find it in the Info.Plist
inside the .app folder).Data
folder as well as the aforementioned Container.Plist file. The Data folder is very interesting. If you change directory (cd) into it you can see that it simulates the user’s Home directory. Of course, all of those are tightly controlled symlinks. The control is being enforced by the Container.plist which contains the SandboxProfileDataValidationRedirectablePathsKey
that dictates which symlinks are approved.mac_execve
, which can be seen in the XNU source code. The __mac_execve
will pretty much load the binary but it will also check the MAC label
to see whether Sandbox should be enforced. At this point, the system is aware that you are going to be Sandboxed but you’re not just yet.libSystem.B
because all the APIs rely on it. At some point during the execution, libSystem.B.initializer
will fall to _libsecinit_setup_secinitd_client
which will then fall to xpc_copy_entitlements_for_pid
to grab the Entitlements from the application binary, and then it will send the entitlements as well as whether the application is supposed to be sandboxed via an XPC message to secinitd
daemon located in /usr/libexec/secinitd
. This message transfer happens at xpc_pipe_route
level. The same function will handle the message receive from the secinitd
daemon which will parse the XPC message received from the process.secinitd
dameon will acknowledge the fact that sandboxing should be enforced if the entitlement is present, then it will call upon the AppSandbox.Framework
to create the sandbox profile
. After the profile is created secinitd
will return an XPC message
containing the CONTAINER_ID_KEY, CONTAINER_ROOT_PATH_KEY, SANDBOX_PROFILE_DATA_KEY
, amongst other data. This information will be parsed by _libsecinit_setup_app_sandbox
which then falls into __sandbox_ms
thus creating the sandbox of the application and containerizing it at runtime.secinitd
daemon. We’re about to dive into Terminal and LLDB, so the following listing may appear very hard to follow. To make it easier on yourself to understand what is going on, it’s best to try to follow the important logic like the messages being passed around and the backtrace to see what function calls we do.xpc_pipe_routine
where the XPC messages are sent and received, and at __sandbox_ms
which is the Sandbox MACF syscall.libxpc.dylib
and we stopped at the xpc_pipe_routine
. Let’s do a backtrace
to see what is going on. We can do that with the bt
command._xpc_uncork_domain
function of libxpc.dylib
. We need the xpc_pipe_create
one. We press c
to continue and backtrace again.xpc_pipe_create
function. Now thanks to Jonathan Levin, I learned that you can use the p (char *) xpc_copy_description($rsi)
to view the message that is being sent through the XPC pipe which is super useful for debugging. We use the RSI
register as the message is the second argument (the first one is the pipe).SECINITD_REGISTRATION_MESSAGE_IS_SANDBOX_CANDIDATE_KEY
is set to bool true
and we do possess the com.apple.security.app-sandbox
entitlement. We’re bound to be sandboxed.secinitd
, let’s see if the sandbox is being created. For that we’re using the second breakpoint we’ve set, the one on __sandbox_ms
. Since the breakpoint is already set, we continue (c) until we hit it._libsecinit_setup_app_sandbox
of libsystem_secinit.dylib
which means that our Sandbox has been created and we’re about to be placed into it as we start. The next few continue commands would finally fall into sandbox_check_common
of libsystem_sandbox.dylib
and then finally into LaunchServices
after which the app is started through AppKit`-[NSApplication init]
.For Developers > Design Documents > Sandbox > OSX Sandboxing Design
|