blob: ea950b33abc322c76d94720fd48f1abb78ceb76b [file] [log] [blame] [view]
Robert Seseke63d8732024-02-02 22:10:011# Chrome Android Sandbox Design
2
3This document discusses the sandbox and process architecture of Chrome on
4Android. Like Chrome's desktop platforms, Android uses a sandbox to isolate and
5de-privilege untrustworthy computing principals. However, the overall
6architecture is materially different than on desktop platforms, while still
7arriving close to the same end result.
8
9## Overall Architecture
10
11The Chrome Android browser process is the main trusted principal in the system,
12it manages and communicates with a network of processes over inter-process
13communication (IPC). The major features of the security architecture are:
14
15- The browser process is protected by the [Android app
16 sandbox](https://source.android.com/docs/security/app-sandbox), which isolates
17 each installed application on the system.
18- Chrome launches its helper processes as Android
19 [Services](https://developer.android.com/reference/android/app/Service).
20- For sandboxed helper processes, the sandbox follows a similar bilayer design
21 as the desktop Linux sandbox. The layer-one sandbox is provided by the
22 [`android:isolatedProcess`](https://developer.android.com/guide/topics/manifest/service-element#isolated)
23 attribute on the Service's manifest definition.
24- Chrome [applies](https://source.chromium.org/chromium/chromium/src/+/main:sandbox/linux/seccomp-bpf-helpers/seccomp_starter_android.h)
25 a layer-two sandbox in the form of a Seccomp-BPF system call filter.
26
27![Diagram of the Android OS components and the parent/child and IPC relationships](android-sandbox-diagram.png)
28
29<!-- Source: https://docs.google.com/drawings/d/11oVsYx_TCrPMglMMW009IFFCStPrLPFbAIVNPp647Lw/edit -->
30
31## Processes
32
33The below sections discuss three IPC transport mechanisms: Binder, UNIX sockets,
34and Mojo. Binder is Android's primary IPC mechanism, implemented with a kernel
35driver and a user `ioctl` client. UNIX socket IPC is used between certain
36Android OS components, and it underpins Chrome's Mojo IPC mechanism. [Mojo
37IPC](../../mojo/README.md) is the main IPC system used in Chrome to communicate
38between components.
39
40### Browser Process
41
42The Chrome browser process on Android is unique compared to the security
43architecture of Chrome on other platforms. On desktop systems, all applications
44typically run as the same user principal (UID), and each application often has
45the same view of the global filesystem and equal access to the files within.
46
47On Android, each installed application is given a distinct user ID (UID) and a
48restricted, scoped storage location. Applications only interact with each other
49using the high-level
50[Intents](https://developer.android.com/guide/components/intents-filters) IPC
51system.
52
53The implications of this are that Chrome on Android should generally be
54less trusting of data coming from other apps. Similarly, Chrome should either
55trust or take care to sanitize data it sends to other apps. For more details see
56[Android IPC Security Considerations](android-ipc.md).
57
58### Helper Processes
59
60Chrome uses helper processes to segment and isolate the work it performs on
61behalf of websites and the user. On desktop platforms, Chrome's browser process
62has a parent-child relationship to the helper processes. But on Android, all
63process creation goes through the Activity Manager and a zygote. The entrypoint
64in Chrome for these processes is the
65[`ContentChildProcessService`](https://source.chromium.org/chromium/chromium/src/+/main:content/public/android/java/src/org/chromium/content/app/ContentChildProcessService.java;drc=4e1b7bc33d42b401d7d9ad1dcba72883add3e2af),
66which has both privileged (un-sandboxed) and sandboxed subclass variants.
67
68The zygote architecture is similar to the [one used on
69Linux](../linux/zygote.md), but the Android OS uses it for all processes on the
70system. This design exists because starting the Android JVM from scratch in each
71new process would be expensive, and the zygote enables cloning the running JVM
72to improve performance and reduce memory usage by sharing non-dirty memory
73pages.
74
75A consequence of this design is that process creation on Android is more
76involved than on other operating systems. Rather than a system call (or two,
77e.g. `fork()` + `execve()`), process creation in Android involves several IPCs
78through the system:
79
801. Browser sends a Binder IPC to Activity Manager for [`Context.bindService()`](https://developer.android.com/reference/android/content/Context#bindService(android.content.Intent,%20android.content.Context.BindServiceFlags,%20java.util.concurrent.Executor,%20android.content.ServiceConnection))
812. Activity Manager sends the zygote an IPC over a privileged UNIX socket to fork a process
823. Zygote responds to Activity Manager with the forked process ID
834. New process sends a Binder IPC to Activity Manager to connect with it
845. Activity Manager sends a Binder IPC to the new process with information about the APK to load
856. Activity Manager sends a Binder IPC channel connecting the new process to the browser process
86process for [`ServiceConnection.onServiceConnected`](https://developer.android.com/reference/android/content/ServiceConnection#onServiceConnected(android.content.ComponentName,%20android.os.IBinder))
87
88In Chrome, after the process is created, the browser process sends a file
89descriptor to the new process over Binder to establish Chrome's Mojo IPC. From
90then on, Chrome primarily uses Mojo IPC between the browser and the helper
91process. The Binder IPC channel is retained in order to control the lifetime of
92the helper process.
93
94### Zygote
95
96Starting with Android API v29, the OS offers applications the ability to create
97per-app zygotes. An `isolatedProcess <service>` can be declared with
98[`android:useAppZygote`](https://developer.android.com/reference/android/R.styleable#AndroidManifestService_useAppZygote)
99and provide a [`ZygotePreload`](https://developer.android.com/reference/android/app/ZygotePreload)
100implementation. This instructs the OS to spawn a new zygote, from the system
101zygote, that will be used to launch all instances of that Service. By giving the
102application the ability to participate via `ZygotePreload`, the application can
103acquire resources and perform initialization that is common to all future
104processes. This extends the benefits of lower initialization time and greater
105memory sharing from the system zygote to individual applications.
106
107## Sandboxing
108
109Similar to the [Linux sandbox design](../linux/sandboxing.md), which uses a
110bilayer sandbox, Chrome on Android also uses two technologies to secure
111low-privilege processes.
112
113### SELinux
114
115The Android OS applies an [SELinux policy](https://source.android.com/docs/security/features/selinux)
116to every process on the system. A full explanation of SELinux is outside the
117scope of this document, but at a high-level it is a [mandatory access control
118mechanism](https://csrc.nist.gov/glossary/term/mandatory_access_control) that
119enforces a capability sandbox. Every object represented in the kernel has an
120associated security label, and the system policy specifies what subjects can do
121to objects. For Chrome, SELinux acts as the layer-one sandbox.
122
123System services have per-service policies, but applications and their components
124are usually assigned to one of three domains:
125
126- [**untrusted_app**](https://cs.android.com/android/platform/superproject/main/+/main:system/sepolicy/private/untrusted_app.te;drc=4aad91d920ad42a7374e7bbd4cb9a50de4e85efb)
127 is the default policy for most user-installed apps
128- [**priv_app**](https://source.android.com/docs/core/permissions/perms-allowlist)
129 is the used for system applications that require powerful capabilities (e.g.
130 backup/restore)
131- [**isolated_app**](https://cs.android.com/android/platform/superproject/main/+/main:system/sepolicy/private/isolated_app.te;drc=941ba723baceac19151560e8a1d2830b9be6493c)
132 is a restrictive sandbox that can be applied via the `<service
133 android:isolatedProcess="true">` tag in an application's manifest
134
135In Chrome, the browser process runs under the **untrusted_app** SELinux domain,
136which enforces separation between distinct apps on the system.
137
138Chrome's sandboxed helper processes (e.g. renderers, utility processes,
139sandboxed Mojo services) run under **isolated_app**. When the Android OS starts
140an **isolated_app** process, it also assigns the process to an ephemeral UID, to
141separate it from other POSIX security principals. The **isolated_app** SELinux
142domain prevents the process from accessing virtually all system services,
143devices, the network, and most of the filesystem.
144
145Chrome's un-sandboxed helper processes (e.g. GPU, un-sandboxed Mojo services)
146run under **untrusted_app** and the same UID as the browser process. This means
147there is no privilege separation between un-sandboxed helper processes and the
148browser process.
149
150A unique difference with Android compared to desktop platforms is that the
151operating system controls the sandbox policy (as a result of it being a
152mandatory access control mechanism). This means that Chrome cannot modify the
153policy, nor create gradations of sandboxes as can be done on other operating
154systems. A process on Android runs at either the same security principal as the
155browser, or in the tightly sandboxed **isolated_app** domain.
156
157### Seccomp-BPF
158
159[Seccomp-BPF](https://www.kernel.org/doc/html/v4.19/userspace-api/seccomp_filter.html)
160is the second layer of the sandbox, which performs kernel attack surface
161reduction. By removing system calls, or filtering specific arguments of system
162calls, some of the complexity provided by the Linux kernel can be walled off
163from a low-privilege process.
164
165The [policy applied to
Andrew Mitchellda2d50ea2024-04-15 11:09:25166Android](https://source.chromium.org/chromium/chromium/src/+/main:sandbox/linux/seccomp-bpf-helpers/baseline_policy_android.h;l=25;drc=f18d3489a59d34c92a8d96ef6a7e7279198a8ec6)
Robert Seseke63d8732024-02-02 22:10:01167is based on the desktop Linux policy. But, additional system calls are permitted
168compared to desktop Linux. The major differences are to allow the JVM to
169function properly and to account for differences in Bionic (Android Libc) vs
170Glibc (standard Linux).
171
172Additionally, the Android OS applies a [seccomp-bpf filter to all
173applications](https://cs.android.com/android/platform/superproject/main/+/main:bionic/libc/seccomp/seccomp_policy.cpp;l=305;drc=704772bda034448165d071f68b6aeca716f4220e).
174This policy is necessarily looser (since it applies to all applications) than
175the one applied by Chrome. But, seccomp-bpf policies stack and can only be made
176more restrictive.