IOS /Mac has a reputation for being “secure”. What security technologies does it have? How does the core “sandbox” technology come true? How can I customize process sandboxed control to reduce security risks for non-sandboxed applications on the Mac platform? This article takes you deep into the world of the sandbox

IOS /Mac security technology

IOS /Mac provides a “defense in depth” security model, like the castle security architecture, as shown below:

From outside to inside: Develop ID signature and gateway, sandbox, POSIX security model and Keychain store encryption. In addition, it also includes network transmission security, APP transmission security, firewall, disk encryption, file safe and so on.

IOS and Mac apps need to be signed and sandboxed, but Mac apps can be signed and sandboxed using DevelopID instead of the App Store. Most of these apps are not sandboxed, so there are some security risks. How do you effectively control the security risks of “unsandboxed” processes? Let’s take the sandbox route

The sandbox concept

“Sandbox |” the sense that gives a person is the process of running in a protected environment, will not make provisions are not allowed to do within the scope; In essence, the access to system resources of the process is monitored and restricted by the system, such as network, some special paths, read and write of files, etc.

Application sandbox restrictions include but are not limited to:

  • Unable to break through directories outside the application directory. The application can only see its own root directory and the sandbox container directory, which is the root directory for iOS/var/mobile/Application/<app-GUID>, the sandbox directory is/var/mobile/containersand/var/containers; For macOS, the sandbox directory is located~/Library/Containers/<appid>Or use itAppGroupFor the~/Library/Group Containers/<application-group-id>. However, you can allow access to files specified by the file selector user..entitlementsSpecified files, as well as temporary directories, command line tool directories, and specific read-only files. For root restrictions, similarchrootSystem call to modify the root effect of the application.
  • No other process on the system can be accessed, and even if a process has the same UID, the application thinks it is the only process executing on the system.
  • You cannot use any hardware device directly unless.entitlementThe hardware equipment specified in the rights file;
  • Unable to generate code dynamically,mmapandmprotectSystem calls (respectively corresponding to those in Machvm_map_enterandvm_map_protectThe underlying implementation of the call) has been modified to prevent any attempt to make writable memory pages executable. The current memory area is modified to be readable and executable, and is not allowed by dynamic code signatureJITOutside of the map, it is not allowed to modify the memory region right.
  • You cannot perform any action other than a subset of what the user can do. The application does not haverootPermissions (except for Apple’s own apps).

You can use the Activity Monitor to view the sandboxed status of the process as follows:

For macOS Catalina and the following operating systems, you can also run the asctl sandbox check –pid [pid] command to check whether sandbox is enabled.

The sandbox principle

Mandatory access control

The implementation of the sandbox relies on an important Mac security feature: Mandatory Access Control (Mac). This feature comes from Trusted BSD, which allows for a more refined security model, adding object-level security and enhancing the crude UNIX model: Restrict access permissions for specific processes to specific files or resources, such as sockets and IPC, rather than just through the UNIX permission model.

The key concept in the MAC is labels, which are used to classify predefined categories. Collections of files or other objects in the system can be classified using labels. If an object requested for access does not provide a matching label, the MAC rejects the access request. MacOS has expanded it to include support for security policies. These security can be applied to a wide variety of operations, not just objects.

The MAC provides a solid foundation from which to add components that do not need to be part of the kernel, but can be in the form of plug-ins to control system security. Special kernel extensions can be registered with the MAC to enforce a security policy. From a kernel perspective, the various system call implementations insert calls to the MAC, so each system call must first be authenticated by the MAC. If the policy module does not register specific callback functions, those callback functions simply return 0(validation passed). The policy module provides the validation logic, and the MAC layer itself does not make any decisions.

The kernel also provides some Mac-specific system calls, most of which are consistent with FreeBSD, such as execve’s Mac-specific system call __mac_EXECv and MAC’s indirect system call wrapper __mac_syscall.

The sandbox architecture

The overall structure of the sandbox is shown as follows:

It mainly includes the following modules:

  • LibSystem. Dylib: providedsandbox_init,sandbox_free_errorEtc. Function.
  • Libsandbox.dylib: provides parsing, compilation, and generation*.sbThe sandboxprofileThe function.
  • Sandbox.kext: Provides system call hook functions
  • Applematch.kext: provides parsingprofileThe function of

The general process of sandbox is as follows:

Sandboxed processes that access system resources through system calls, such as open to open a file, fall from user mode into kernel mode. Because the system call is “plugged” into the MAC layer check, it is intercepted to traverse the check policy module. Here system startup when loading the sandbox. Kext sandbox kernel extension drive, as well as AppleMobileFileIntegrity. Kext (AMFI) signature calibration kernel extensions, and register to MAC mandatory access layer. Therefore, all system calls of sandboxed processes are filtered by the two policy modules for policy enforcement to prohibit or permit the system calls, thus limiting the ability of sandboxed processes to access system resources.

How is the sandboxed process recognized by the system and registered with the sandbox. Kext policy module? Don’t worry. We’ll take our time. All processes rely on the libsystem.b.dylib dynamic library, as shown below:

When the process starts loading the dynamic library, sandboxed permissions are extracted from the program’s executable and sent to the Secinitd daemon via an XPC message. The daemon calls AppSandbox.framework to create a sandbox configuration file, and then invokes the __sandbox_ms (__mac_syscall) system call to enforce sandboxed permission policies through sandbox.kext. The whole process is shown in the figure below:

For sandboxed process permission, entitlements can be viewed through COdesign -D — Entitlements :- [exec_file] as shown in the following figure:

Process sandbox control use and implementation

From the above analysis of sandbox principle, it can be seen that the implementation of sandbox process in the user layer mainly relies on the libsandbox.dylib dynamic library. The dynamic library contains the main apis for sandbox implementation, including but not limited to the following apis:

/* Open the sandbox @param profile Flags must be SANDBOX_NAMED. Errorbuf returns an error message @return 0 and errorbuf NULL -> SUCCESS-1 and errorbuf -> failed */
int sandbox_init(const char *profile, uint64_t flags, char **errorbuf);
// Release the sandbox error buffer
void sandbox_free_error(char *errorbuf);
Copy the code

A process can actively enter the sandbox by calling sandbox_init, where profile configuration items include the following:

The above configurable items can be implemented to restrict network, file access, and pure computing without applying system resources. Example code is as follows:

#include <sandbox.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>

int main(int argc, const char * argv[]) {
    
    char *error_buf = NULL;
    if(sandbox_init(kSBXProfileNoWrite, SANDBOX_NAMED, &error_buf) ! =0)
        perror("sandbox_init error:");
    
    FILE *fp = fopen("/tmp/sandbox.txt" , "w");
    if(! fp) { perror("fopen error:");
        return 1;
    }
    
    char read_buf[1024] = {0};
    while(gets(read_buf) ! =NULL) {
        fwrite(read_buf, strlen(read_buf), 1, fp);
    }
    
    fclose(fp);
    
    return 0;
}
Copy the code

Fopen error:: Operation not permitted fopen :: Operation not permitted Because kSBXProfileNoWrite disables any file write, such as fopen(” XXX “, “w”), or fwrite(), there is no restriction for fopen(” XXX “, “r”), or file descriptors that are already open before the sandbox is opened are still available.

Although the sandbox_init interface has been explicitly deprecated, it is still available, as chrominum does. If kSBXProfileNoWrite is not writable, the child process does not have the right to write. However, for a process that has been sandboxed, you cannot call the upload API again, otherwise there will be a conflict error!

In addition to the pre-configured configuration files above, OS X’s sandbox-wrapper command, sandbox-exec, provides a flexible configuration syntax that allows the creation of a custom sandbox that blacklists or whitelists the specific functionality of the application executed in it. This tool is actually a wrapper around sandbox_init and is executed before a fork/exec call. Its core implementation is as follows:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h> // fchmod
#include <sandbox.h>
#include "sandbox.h" // My sandbox.h

typedef int bool;
#include <dlfcn.h>

void usage(void)
{
	
	fprintf(stderr."Usage: sandbox-exec [options] command [args]\nOptions:\n -f profile-file Read profile from file.\n -n profile-name Use pre-defined profile.\n -p profile-string Specify profile on the command line.\n -D key=value Define a profile parameter.\n -t trace_file Trace operations to trace_file\n Exactly one of -f, -n, -p must be specified.\n");

	exit(0x40);

} // usage


int debug = 0;
#define dprintf if (debug) printf

int main (int argc, char **argv)
{

	debug = (getenv ("JDEBUG") != NULL);
	// This is as close as possible to the decompilation of OS X's (10.11.4) sandbox-exec
	// including calling sandbox_create_params() before processing arguments. 

	sbProfile_t *compiled_profile;

	char *err = NULL;

	sbParams_t *params=sandbox_create_params();

	if(! params) {fprintf(stderr."Can't create params! \n"); exit(1); }if (argc < 2) { usage(); }



	int opt;

	char *profile = NULL;
	int cmd = 0;
	char *profileName = NULL;
	char *profileString = NULL;
	char *tracePath = NULL;

	while ((opt = getopt(argc,argv,"D:c:de:f:n:p:t:")) > - 1)
	{
		switch (opt)
		{
			case 'f':  profile = optarg; break;
			case 'n':  profileName = optarg; break;
			case 'p':  profileString = optarg; break;
			case 't':  tracePath = optarg; break;
		
			default: usage();
		}
	}

	cmd = optind;
	
	if (tracePath && profileName)
	{
		fprintf(stderr."tracing isn't implemented for named profiles; use -f or -p to specify a profile\n");		
		exit(0x40);
	}

	//compiled_profile = sandbox_compile_entitlements ("no-internet", params, &err);


	if (profile) compiled_profile = sandbox_compile_file (profile, params, &err);

	// The built-in profiles:
	// ----------------------
	// kSBXProfileNoInternet (no-internet)
	// kSBXProfileNoWriteExceptTemporary (no-write-except-temporary)
	// kSBXProfileNoWrite (no-write)
	// kSBXProfileNoNetwork (no-network)
	// kSBXProfilePureComputation (pure-computation)

	if (profileName) compiled_profile = sandbox_compile_named (profileName, params, &err);
	if (profileString) compiled_profile = sandbox_compile_string (profileString, params, &err);

	//sandbox_set_param (params, "x", "y");
	if(! compiled_profile) {fprintf(stderr."No compiled profile. Error: %s\n", err); exit(2); } 


	int dump= 1;
	if (dump && compiled_profile->blob)
	{
	fprintf(stderr."Profile: %s, Blob: %p Length: %d\n",
			(compiled_profile->name? compiled_profile->name : "(custom)" ), 
                         compiled_profile->blob, compiled_profile->len);
	int fd = open("/tmp/out.bin", O_WRONLY | O_TRUNC| O_CREAT);
	fchmod (fd, 0666);
	write(fd, compiled_profile->blob, compiled_profile->len);
	fprintf(stderr."dumped compiled profile to /tmp/out.bin\n");
	}

	int flags = 0;
	int rc = 0;
	if (tracePath) { 
#ifdef SB459
		
		rc = sandbox_set_trace_path(compiled_profile,tracePath); 
#else
		void *sblibhandle = dlopen ("libsandbox.dylib", RTLD_GLOBAL);

		typedef int sstp(void *, char *);
		sstp * sandbox_set_trace_path = dlsym (sblibhandle, "sandbox_set_trace_path");

		if(! sandbox_set_trace_path)fprintf(stderr."Warning: Tracing not supported in this sandbox version (can't get set_trace_path - %p)\n", sblibhandle);
		else {
			rc = sandbox_set_trace_path(compiled_profile,tracePath); 

		}
#endif
		if (rc == 0) fprintf(stderr."Tracing to %s\n", tracePath);
		else fprintf(stderr."Tracing error - Unable to trace to %s\n", tracePath);

	} 


	fprintf(stderr."Applying container\n");
	rc =  sandbox_apply_container (compiled_profile, flags);

	if(rc ! =0) { perror("sandbox_apply_container"); }
	
	fflush(NULL);
	if (compiled_profile) sandbox_free_profile(compiled_profile);
	fprintf (stderr."EXECING %s\n", argv[optind]);
	execvp (argv[optind], argv+optind);

	perror("execvp");


}
Copy the code

The Chrome sandbox is also based on the libsandbox.dylib API, which is visible in content/common/sandbox_mac.mm. The latest source visible chromium.googlesource.com/chromium/sr… .

Sandbox restricts the following types of resources:

  • Files: read, write, and any type of operation
  • IPC: Posix and SysV
  • Mach
  • Network: input/output
  • Process: execute and clone
  • signal
  • Sysctl
  • System

The rules for using sandbox-exe are as follows:

$ sandbox-exec [-f profile-file] [-n profile-name] [-p profile-string] [-D key=value ...] command [arguments ...]
Copy the code

You can apply -f to the configuration file, -n to the configuration name, and -p directly to the configuration string, as follows:

$sandbox - exec - f/usr/share/sandbox/BSD. Sb/bin/lsCopy the code
$ sandbox-exec -n no-internet ping www.google.com
Copy the code

You can refer to the sandbox configuration file of the system. The path includes:

  • /Library/Sandbox/Profiles
  • /System/Library/Sandbox/Profiles
  • /usr/share/sandbox

For example, restrict access to specific ports as follows:

$ sandbox-exec -p '
(version 1)
(allow default)
(deny network-outbound (remote ip "*:80"))' curl www.baidu.com
Copy the code

Specific syntax rules can be found in Apple’s Sandbox Guide V1.0@ 2011

Thank you for friendship

[1] macOS security

[2] Security and Your Apps-wwdc15

[3] Sandbox analysis of iOS and macOS

[4] App Sandbox Design Guide

[5] in-depth analysis of Mac OSX&iOS operating systems

[6] The basics of Apple sandbox research