Note: This chapter describes property list keys specific to the macOS implementation of App Sandbox. They are not available in iOS.
In short, Windows Sandbox is half app, half virtual machine. It lets you quickly spin up a virtual clean OS imaged from your system’s current state so that you can test programs or files in a secure environment that’s isolated from your main system. When you close the sandbox, it destroys that state. MacOS has a build in Sandbox feature which may help you but does not exactly have the same functionality as Sandboxy. This Paolo Fabio Zaino's Blog post from 2015 explains how to run Applications in a Mac OS X sandbox. Download sandbox for Mac to modulates 2 audio files in real-time using a variety of methods.
In your macOS Xcode project, configure fine-grained security permissions by enabling settings in the Summary tab of the target editor. These settings, in turn, add Boolean values to entitlement keys in the target’s
.entitlements property list file. The values are then incorporated into the target’s code signature when you build the project.
You can think of using App Sandbox entitlements as a two-step process:
At runtime, if a target requires a capability or a system resource for which the target isn’t entitled, the sandbox daemon (
sandboxd ) logs a violation message to the console.
For more information about App Sandbox, read App Sandbox Design Guide.
App Sandbox Entitlement Keys
This section describes the keys you can use to confer capabilities to a sandboxed app in macOS. The first key enables App Sandbox; the others configure the sandbox. If App Sandbox is not enabled, the other keys in this section are meaningless.
The value to use for any of these keys is a Boolean
YES or NO , with the default value in each case being NO . If you are editing the .entitlements file directly in a text editor, the corresponding Boolean values to use are <true/> and <false/> . The default value for each key is false, so you can (and generally should) leave out the entitlement entirely rather than specifying a false value.
In cases where there are read-only and read/write entitlement key pairs, use of either key in the pair is mutually exclusive with the other.
Add these keys by using the Summary tab of the Xcode target editor. You can also add them directly to a target’s
.entitlements file with the Xcode property list editor.
For information on additional entitlements for handling special circumstances, see App Sandbox Temporary Exception Entitlements.
For each key in this table, providing a Boolean value of
YES enables the corresponding capability (unless otherwise noted).
Capability
Enables App Sandbox for a target in an Xcode project
Allows access to group containers that are shared among multiple apps produced by a single development team, and allows certain additional interprocess communication between the apps
Supported in macOS v10.7.5 and in v10.8.3 and later. The format for this attribute is described in Adding an App to an App Group.
Read-only access to the user’s Movies folder and iTunes movies
For details, see Enabling Access to Files in Standard Locations.
Read/write access to the user’s Movies folder and iTunes movies
For details, see Enabling Access to Files in Standard Locations.
Read-only access to the user’s Music folder
For details, see Enabling Access to Files in Standard Locations.
Read/write access to the user’s Music folder
For details, see Enabling Access to Files in Standard Locations.
Read-only access to the user’s Pictures folder
For details, see Enabling Access to Files in Standard Locations.
Read/write access to the user’s Pictures folder
For details, see Enabling Access to Files in Standard Locations.
Communication with AVB devices
For details, see Enabling Hardware Access.
Interaction with Bluetooth devices
For details, see Enabling Hardware Access.
Capture of movies and still images using the built-in camera, if available
For details, see Enabling Hardware Access.
Interaction with FireWire devices (currently, does not support interaction with audio/video devices such as DV cameras)
For details, see Enabling Hardware Access.
Recording of audio using the built-in microphone, if available, along with access to audio input using any Core Audio API that supports audio input
For details, see Enabling Hardware Access.
Interaction with serial devices
For details, see Enabling Hardware Access.
Interaction with USB devices, including HID devices such as joysticks
For details, see Enabling Hardware Access.
Read/write access to the user’s Downloads folder
For details, see Enabling Access to Files in Standard Locations.
Use of app-scoped bookmarks and URLs
For details, see Enabling Security-Scoped Bookmark and URL Access.
Use of document-scoped bookmarks and URLs
For details, see Enabling Security-Scoped Bookmark and URL Access.
Read-only access to files the user has selected using an Open or Save dialog
For details, see Enabling User-Selected File Access.
Read/write access to files the user has selected using an Open or Save dialog
For details, see Enabling User-Selected File Access.
Allows apps to write executable files.
For details, see Enabling User-Selected File Access.
Child process inheritance of the parent’s sandbox
Sandbox Mac Apps
For details, see Enabling App Sandbox Inheritance.
Network socket for connecting to other machines
For details, see Enabling Network Access.
Network socket for listening for incoming connections initiated by other machines
For details, see Enabling Network Access.
com.apple.security.personal-information.addressbook
Read/write access to contacts in the user’s address book; allows apps to infer the default address book if more than one is present on a system
Timing app mac similar. For details, see Enabling Personal Information Access.
Read/write access to the user’s calendars
For details, see Enabling Personal Information Access.
Use of the Core Location framework for determining the computer’s geographical location
For details, see Enabling Personal Information Access.
Printing
For details, see Enabling Hardware Access.
Ability to use specific AppleScript scripting access groups within a specific scriptable app
For details, see Enabling Scripting of Other Apps.
Enabling App Sandbox
You enable App Sandbox individually for each target in an macOS Xcode project. For example, you may design a project as a main app, and some helpers in the form of XPC services. You then enable and configure the sandbox for each target individually.
To learn how to enable App Sandbox for your macOS app, which includes performing code signing, see App Sandbox Quick Start in App Sandbox Design Guide. The essential step is to ensure that the target editor checkbox named in Table 4-1 is selected.
Enabling User-Selected File Access
Xcode provides a pop-up menu, in the Summary tab of the target editor, with choices to enable read-only or read/write access to files and folders that the user explicitly selects. When you enable user-selected file access, you gain programmatic access to files and folders that the user opens using an
NSOpenPanel object, and files the user saves using an NSSavePanel object.
Certain other user interactions, such as dragging items to your app or choosing items from the Open Recent menu, automatically expand your sandbox to include those items. Similarly, when macOS resumes an app after a reboot, the sandbox is automatically expanded to include any items that are automatically opened.
To enable user-selected file access in your app, use the Xcode target editor setting shown in Table 4-2.
Note: If your app needs to create executable files that are typically executed in some way other than through Launch Services (shell scripts, for example), you should also specify the
com.apple.security.files.user-selected.executable entitlement.
By default, when writing executable files in sandboxed apps, the files are quarantined. Gatekeeper prevents quarantined executable files and other similar files (shell scripts, web archives, and so on) from opening or executing unless the user explicitly launches them from Finder.
If those executables are tools that are intended to run from the command line, such as shell scripts, this presents a problem. With this flag, the file quarantine system allows the app to write non-quarantined executables so that Gatekeeper does not prevent them from executing.
This entitlement does not have an Xcode checkbox, and thus must be added to your app’s entitlement property list manually. For details, see App Sandbox Entitlement Keys.
Enabling Access to Files in Standard Locations
In addition to granting user-selected file access, you can employ entitlements to grant programmatic file access to the following user folders:
The Xcode control for enabling Downloads folder access is a checkbox; the controls for enabling access to these other folders are pop-up menus.
When you enable programmatic access to the user’s Movies folder, you also gain access to their iTunes movies.
Reopening of files by macOS using Resume does not require the presence of any entitlement key.
To enable programmatic access to specific folders, use the Xcode target editor settings shown in Table 4-3.
Enabling Security-Scoped Bookmark and URL Access
If you want to provide your sandboxed app with persistent access to file system resources, you must enable security-scoped bookmark and URL access. Security-scoped bookmarks are available starting in macOS v10.7.3.
To add the
bookmarks.app-scope or bookmarks.document-scope entitlement, edit the target’s.entitlements property list file using the Xcode property list editor. Use the entitlement keys shown in Table 4-4, depending on which type of access you want. Use a value of <true/> for each entitlement you want to enable. You can enable either or both entitlements.
For more information on security-scoped bookmarks, read Security-Scoped Bookmarks and Persistent Resource Access in App Sandbox Design Guide.
Enabling Network Access
Xcode’s Network checkboxes in the Summary tab of the target editor let you enable network access for your app.
![]()
To enable your app to connect to a server process running on another machine (or on the same machine), enable outgoing network connections.
To enable opening a network listening socket so that other computers can connect to your app, allow incoming network connections.
Note: Both outgoing and incoming connections can send and receive data. The sole difference is in whether your app is initiating the connection or is receiving connections initiated by other apps or other hosts.
To enable network access, use the Xcode target editor settings shown in Table 4-5.
Enabling Hardware Access
To allow a sandboxed target to access hardware services on a system—USB, printing, or the built-in camera and microphone—enable the corresponding setting in the Summary tab of the Xcode target editor.
To enable access to hardware, use the Xcode target editor settings shown in Table 4-6.
To allow access to hardware devices for which no checkbox exists in Xcode’s user interface, you must manually add the appropriate entitlement to your app’s entitlements property list. These additional entitlements are listed in Table 4-7. All of these keys take a Boolean value.
Enabling Personal Information Access
A user’s personal information is inaccessible to your sandboxed app unless you grant access using the appropriate settings.
To enable access to personal information, use the Xcode target editor settings shown in Table 4-8.
Adding an App to an App Group
The
com.apple.security.application-groups (available in macOS v10.7.5 and v10.8.3 and later) allows multiple apps produced by a single development team to share access to a special group container. This container is intended for content that is not user-facing, such as shared caches or databases.
In addition, this attribute allows the apps within the group to share Mach and POSIX semaphores and to use certain other IPC mechanisms among the group’s members. For additional details and naming conventions, read “Mach IPC and POSIX Semaphores and Shared Memory” in App Sandbox Design Guide.
The value for this key must be of type
array , and must contain one or more string values, each of which must consist of your development team ID, followed by a period, followed by an arbitrary name chosen by your development team. For example:
The group containers are automatically created or added into each app’s sandbox container as determined by the existence of these keys. The group containers are stored in
~/Library/Group Containers/<application-group-id> , where <application-group-id> is one of the strings from the array. Your app can obtain the path to the group containers by calling the containerURLForSecurityApplicationGroupIdentifier: method of NSFileManager .
Enabling App Sandbox Inheritance
If your app employs a child process created with either the
posix_spawn function or the NSTask class, you can configure the child process to inherit the sandbox of its parent. However, using a child process does not provide the security afforded by using an XPC service.
Important: XPC (as described in External Tools, XPC Services, and Privilege Separation) complements App Sandbox and is the preferred technology for implementing privilege separation in an macOS app. Before using a child process, consider using an XPC service instead.
To enable sandbox inheritance, a child target must use exactly two App Sandbox entitlement keys:
com.apple.security.app-sandbox and com.apple.security.inherit . If you specify any other App Sandbox entitlement, the system aborts the child process. You can, however, confer other capabilities to a child process by way of iCloud and notification entitlements.
The main app in an Xcode project must never have a
YES value for the inherit entitlement.
To add the
inherit entitlement, edit the target’s .entitlements property list file using the Xcode property list editor. Use the entitlement key shown in Table 4-9 with a value of <true/> .
Note: This property causes the child process to inherit only the static rights defined in the main app’s entitlements file, not any rights added to your sandbox after launch (such as PowerBox access to files).
If you need to provide access to files opened after launch, you must either pass the data to the helper or pass a bookmark to the child process. The bookmark need not be a security-scoped bookmark, but it can be, if desired.
If you are using other APIs to create child processes (such as
NSWorkspace ) and wish to have a shared container directory, you must use an app group.
Enabling Scripting of Other Apps
If your app needs to control another scriptable app, your app can use the scripting targets entitlement to request access to one or more of the scriptable app’s scripting access groups.
Note: Before you can use this entitlement, the scriptable app must provide scripting access groups. If it does not, you can still control the app, but you use a temporary exception entitlement instead. In some cases, you may use both
scripting-targets entitlement and a temporary entitlement together, to provide support across different versions of the OS. For more information, see Apple Event Temporary Exception.
The scripting target entitlement contains a dictionary where each entry has the target app’s code signing identifier as the key, and an array of scripting access groups as the value. Scripting access groups are identified by strings and are specific to an app. For example, the following entry would grant access to composing mail messages with Apple’s Mail app:
For more information about how to add scripting access groups to an app, watch WWDC 2012: Secure Automation Techniques in OS X and read the manual page for sdef .
Copyright © 2017 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2017-03-27
The App Sandbox, originally introduced in Mac OS X Leopard as “the Seatbelt”, is a macOS security feature modeled after FreeBSD’s Mandatory Access Control (left unabbreviated for clarity) that serves as a way to restrict the abilities of an application beyond the usual user- and permission-based systems that UNIX offers. The full extent of the capabilities the sandbox manages is fairly broad, ranging from file operations to Mach calls, and is specified in a custom Scheme implementation called the Sandbox Profile Language (SBPL). The sandbox profiles that macOS ships with can be found in /System/Library/Sandbox/Profiles, and while their format is technically SPI (as the header comment on them will tell you) there is fairly extensive third-party documentation. The implementation details of sandboxing are not intended to be accessed by third-party developers, but applications on Apple’s platforms can request (and in some cases, such as new applications distributed on the Mac App Store and all applications for Apple’s embedded platforms, must function in) a sandbox specified by a fixed, system-defined profile (on macOS, application.sb). Barring a few exceptions (which usually require additional review and justification for their use) this system-provided sandbox provide an effective way to prevent applications from accessing user data without consent or performing undesired system modifications.
In January I discovered a flaw in the implementation of the sandbox initialization procedure on macOS that would allow malicious applications distributed through the Mac App Store to circumvent the enforcement of these restrictions and silently perform unauthorized operations, including actions such as accessing sensitive user data. Apple has since implemented changes in the Mac App Store to address this issue and the technique outlined below should no longer be effective.
Sandbox initialization on macOS
Sandboxing is enforced by the kernel and present on both macOS and Apple’s iOS-based operating systems, but it is important to note that third party code is not required to run in a sandbox on macOS. While the use of the platform sandbox is mandatory for third-party software running on embedded devices, on Macs it is rarely used by applications distributed outside of the Mac App Store; even on the store there are still a couple of unsandboxed applications that have been grandfathered into being allowed to remain for sale as they were published prior to the 2012 sandboxing deadline. A lesser known, but likely related fact is that processes are not born sandboxed on macOS: unlike iOS, where the sandbox is applied by the kernel before the first instruction of a program executes, on macOS a process must elect to place itself into the sandbox using the “deprecated”
sandbox_init(3) family of functions. These themselves are wrappers around the __sandbox_ms function, an alias for __mac_syscall from libsystem_kernel.dylib in /usr/lib/system. This design raises an important question: if a process chooses to place itself in a sandbox, how does Apple require it for apps distributed through the Mac App Store?
Experienced Mac developers already know the answer: Apple checks for the presence of the
com.apple.security.app-sandbox entitlement in all apps submitted for review, and its mere existence magically places the process in a sandbox by the time code execution reaches main . But the process isn’t actually magic at all: it’s performed by a function called _libsecinit_initializer inside the library libsystem_secinit.dylib, also located at /usr/lib/system:
_libsecinit_initializer calls _libsecinit_appsandbox , which (among other things) copies the current process’s entitlements, checks for the com.apple.security.app-sandbox in them, and calls __sandbox_ms after consulting with the secinitd daemon. So this answers where the sandbox is applied, but doesn’t explain how: for that, we need to look inside libSystem.
libSystem is the standard C library on macOS (see
intro(3) for more details). While it vends system APIs, by itself it does very little; instead, it provides this functionality by re-exporting all the libraries inside of /usr/lib/system:
Like most standard libraries, the compiler will automatically (and dynamically) link it into your programs even if you don’t specify it explicitly:
When a program is started, the dynamic linker will ensure that libSystem’s initializer functions are called, which includes the function that calls
_libsecinit_initializer . As dyld ensures that libSystem’s initializer is run prior to handing off control to the app’s code, this ensures that any application that links against it will have sandboxing applied to it before it can execute its own code.
Bypassing sandbox initialization
As you may have guessed, this process is problematic. In fact, there are actually multiple issues, each of which allows an application with the
com.apple.security.app-sandbox entitlement to bypass the sandbox initialization process.
dyld interposing
dyld interposing is a neat little feature that allows applications to tell the dynamic linker to “interpose” an exported function and replace it with another by including a special
__DATA,__interpose section in their binary. Since _libsecinit_appsandbox is exported by libsystem_secinit.dylib so that it can be called by libSystem, we can try interposing it with a function that does nothing:
When interposing was first introduced, it would only be applied when a library was preloaded into a process using the
DYLD_INSERT_LIBRARIES environment variable. However, on newer OSes this functionality has been improved to work for any linked libraries as well, which means all we have to do to take advantage of this feature is put this code in a framework and link against it in our main app. Since interposing is applied before image initializers we will be able to prevent the real _libsecinit_initializer from running and thus __sandbox_ms being called. Success!
As this technique allowed an application that appears to be sandboxed (possessing the
com.apple.security.app-sandbox entitlement) to interfere with its own initialization process, I reported this issue to Apple on January 20th and explained that such an app might be able to be submitted to the App Store and get past app review. On March 19th, I received a reply from Apple stating that App Store applications are prevented from being interposed, which was news to me. Apparently right after I submitted my original report Apple added an additional check in dyld, one so new that it’s still not in any public sources:
While the dyld source for
configureProcessRestrictions only shows five flags being read from amfi_check_dyld_policy_self , the binary clearly checks a sixth: 1 << 6 . (configureProcessRestrictions has been inlined here into its caller, dyld::_main .) I still do not know what its real name is but it’s used later in dyld::_main to control whether interposing is allowed. This means we can’t interpose _libsecinit_initializer –we’ll have to prevent it from from being called instead.
Update, 6/10/19
With the code to dyld released, we can see that the flag is called
AMFI_DYLD_OUTPUT_ALLOW_LIBRARY_INTERPOSING . Interestingly, there are some applications that are exempted from the check in AMFI’s macos_dyld_policy_library_interposing , meaning that they are still susceptible to this issue:
Static linking
Linking against libSystem causes dyld to call
_libsecinit_initializer , so it’s logical to try to avoid having anything to do with dyld at all. This is fairly strange to do on macOS, as it does not have a stable syscall interface, but with the right set of compiler flags we can make a fully static binary that needs to no additional support to run.
Fun fact
We know that this must be possible because Go used to do it, until they got tired of new versions of macOS breaking everything and gave up trying to make system calls themselves. Go programs as of Go 1.11 now use libSystem.
Unfortunately, macOS does not ship with a crt0.o that we can statically link, so using just the
-static flag does not work:
But if we’re jettisoning the standard library, we might as well get rid of the C runtime as well, defining our own
start symbol:
No dyld means no code that can arrange a call
_libsecinit_initializer , so we’re free to do whatever we like without restriction. However, not having libSystem and dyld to support us means we cannot use dynamic linking and need to make raw system calls for everything, which is a bit of a pain. One way to resolve this would be to keep the unsandboxed code short–just a couple of calls to acquire a handle on restricted resources–then stash that away before execve ing a new dynamically linked binary, restoring the process to a sane state. When responding to Apple with a new sample program based on this idea, I simply open ed a file descriptor for the home directory (you can locate the directory without any syscalls by pulling the current username from the apple array on the stack during process initialization) and then once that succeeds executed an inner binary. The new file descriptor was preserved for across the execve call and became accessible to the inner application, even though that one was dynamically linked and had the sandbox applied to it as usual.
Dynamically linking against nothing
Statically linking works, but it’s somewhat inconvenient: either you perform the work of the dynamic linker yourself if you want to do anything non-trivial, or you
execve a new binary. It’s actually worse than that though, because there’s an additional complication: executing a new binary causes a hook in the AppleMobileFileIntegrity kernel extension to run, and when System Integrity Protection is enabled this hook (for reasons unknown to me) checks to see if the process has a valid dyld signature:
The strange pointer arithmetic and mask is really a check for
CS_DYLD_PLATFORM , which the comment helpfully states is set if the “dyld used to load this is a platform binary”. Since we didn’t use dyld at all, this isn’t set and we can’t execve . While malicious applications willing to do a bit of work can still “fix” their process without blowing it away, I figured I might as well figure out a way to construct a new one.
Since the hook wants us to have a valid dyld, we should probably just link dynamically. As we mentioned before, this makes the compiler automatically bring in libSystem (and with it, the libsystem_secinit.dylib initializers), which we don’t want. I couldn’t find out a way to get the linker to not automatically insert the load command for libSystem, but we can get essentially the same result by modifying the binary ourselves afterwards to delete that specific command. I found a Mach-O editor online that was slightly crashy but worked well enough for this purpose. Unfortunately, removing the load command isn’t enough: dyld specifically checks for libSystem “glue” before running our code, and as we don’t have a libSystem at all it aborts execution.
However, there’s one way around this: if we use a
LC_UNIXTHREAD rather than a LC_MAIN load command, dyld will pass execution to us without checking for libSystem (as it thinks we have linked against crt1.o instead). Both load commands specify the entrypoint of the executable, but LC_MAIN is the “new” way of doing so. LC_UNIXTHREAD specifies the entire thread state, but LC_MAIN only points to the “entry offset” where code execution should begin–the linker sets this to where main is, unless you’ve used -e to change it. The compiler uses it for dynamically linked binaries because it expects libSystem to set all the thread state prior to calling the entrypoint function.
The linker flag
-no_new_main tells the linker to use LC_UNIXTHREAD instead of LC_MAIN for dynamically linked executables, but it has been silently ignored for years (apparently, this has something to do with rdar://problem/39514191). This means to generate the binary we’ll have to go back in time and download an old toolchain that accepts this flag. The one that Xcode 5.1.1 ships with does nicely.
Fun fact
I have a friend who refers to Xcode 5.1.1 as “the good toolchain” because it supports everything.
Once we use that to create a binary, upon running it we have a valid dyld in our process and unsandboxed code execution so we can just continue as we did in the statically linked case, as this will satisfy AMFI’s checks.
Final thoughts
I submitted the final example to Apple just before the initial 90-day disclosure deadline of April 20th, and when they requested an extension to work on the new information I provided them with an additional 30 days. Apple says it has made changes in the Mac App Store to address this issue during that period, and although I don’t really have a good way to check if or how the change works I would guess that it simply looks for and rejects applications using techniques similar to the ones described above.
dyld is a fairly complicated system and it has many useful features, but these features along with the fact that it runs in-process makes it nontrivial to protect against control flow subversion early in the initialization process. Applying sandboxing in the kernel itself, as iOS does, is probably a better solution in the long run, as the bugs I found here were fairly straightforwards and exploited logic errors rather than undefined behavior in the language. Perhaps we will see such a change in the future.
Mac Os X Run App In Sandbox
The code I submitted to Apple to demonstrate the issue is available online.
TimelineOs X Sandbox
Comments are closed.
|
AuthorWrite something about yourself. No need to be fancy, just an overview. ArchivesCategories |