Since 2012, all apps on the Mac App Store must run in an app sandbox, which restricts access to system resources unless explicitly required. The secure sandbox isolates the app and defines access controls, protecting users from malicious code with undesired behaviour. Aug 04, 2015 17 thoughts on “ macOS: How to run your Applications in a Mac OS X sandbox to enhance security ” Pingback: Maximum security and privacy using Mac OS sandbox and Tor browser bundle Paolo Fabio Zaino's Blog. Pingback: Doing app builds in a sandbox. Best Wordpress Themes - Reviews. MacOS Big Sur also brings universal apps, which can run on an Intel- or M1-based Mac. Adobe is bringing universal versions of its apps, starting with Lightroom next month and Photoshop early next.
![]()
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:
Shelves app for mac shortcut. 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 . Best usb recovery software mac. 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!
Sandbox Mac Apps
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”. Not finding allow apps from anywhere mac os sierra os. 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.
Mac Os X Run App In Sandbox Mode
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.
X Run Servers
The code I submitted to Apple to demonstrate the issue is available online. Connect to mac using vnc.
Timeline
Beside the pre-configured profiles, OS X’s sandbox wrapper command
sandbox-exec provides a flexible configurationsyntax that allows one to create a customized sandbox that either blacklists or whitelists specific abilities of theapplication executed within.
A sandbox profile defines what a application running inside the sandbox should be able to do. Grasshopper rhino 5 mac download. The following exampleprofile
no-network.sb allows anything except any kind of network access. This might be useful if you want aapplication to keep your data private instead of sending it home:
Sandbox For Mac
Replacing
allow by deny would deny anything except networking. It’s that easy. Live mobile number tracker software free download for pc.
Other abilities include
file-read , signal , ipc-posix-shm , process , mach-lookup etc. Some need additionalparameters like file- or folder names.
The following link provides additional examples of sandbox profiles:
You can run any CLI or desktop application by executing it’s Mach-O binary file through
sandbox-exec . The followingcommand runs VLC player without network access:
Mac Os X Run App In Sandbox Windows 10
https://qaxciz.weebly.com/blog/how-to-delete-apps-on-macos. Please note that while the sandbox mechanism is good enough for almost any use case, it still does not provide perfectsecurity, described e.g. here: http://www.coresecurity.com/content/apple-osx-sandbox-bypass
I run this site without advertisement of any kind. All information is free and my only goal is to give back something to the amazing free software development community. If you find some value in this, please consider donating me a cup of coffee using PayPal. Thank you so much!
Comments are closed.
|
AuthorWrite something about yourself. No need to be fancy, just an overview. ArchivesCategories |