# Android IPC Security Considerations

Generally Chrome communicates between its processes using the
[Mojo](../../mojo/README.md) [inter-process communication (IPC)
mechanism](mojo.md). For most features, this is the preferred IPC mechanism to
use. However, as an Android application, there are certain interactions with
other applications and the Android OS that necessitate using different IPC
mechanisms to communicate. This document covers security concerns related to
those Android-specific IPC mechanisms.

The Chrome browser process is typically the only process type that will interact
with these different IPC mechanisms.

## Intents

[Intents](https://developer.android.com/guide/components/intents-filters) are
the most common type of inter-process communication mechanism on Android. They
are most commonly used to start Activities and they internally carry data
associated with that Activity (e.g. using the `ACTION_SEND` Intent to share a
piece of content and including either text or image data in the Intent body).

### Inbound Intents

Because any application can dispatch Intents with Chrome as the receiver, when
receiving an inbound Intent, you should never fully trust the data contained
within. Data sent from other applications could be malicious or malformed, and
so you must validate or sanitze the data before passing it to other trusted
components of the browser process. Intents are handled in Java though, so
following the [Rule of 2](rule-of-2.md) is generally easy. (Though take note
that certain Android classes are just Java wrappers around native code, which
would not be considered safe by that rule.)

It is **fundamentally impossible** to determine the sender of an Intent, so the
security model of your feature cannot depend on authenticating the sender. Do
not trust `Intent.EXTRA_REFERRER`. See also the discussion below about
[capability tokens](#capability-tokens).

One way to authorize Intents is to use the system's
[`android:permission`](https://developer.android.com/guide/topics/permissions/overview#permission_enforcement)
attribute on a component's (e.g. Activity, Service, etc.) manifest declaration.
You can [define a custom permission](https://developer.android.com/guide/topics/permissions/defining) and
set the `android:protectionLevel` of the permission to `"signature"` or
`"signatureOrSystem"` to restrict access to just components signed by the same
certificate (or trusted system components).

## Outbound Intents {#outbound-intents}

There are [two types of Intents](https://developer.android.com/guide/components/intents-filters?hl=en#Types):
implicit and explicit. With implicit Intents, the receiving application is not
specified by the sender and the system uses a resolution process to find the
most suitable component to handle it. An implicit Intent can sometimes result in
a chooser being shown to the user when multiple applications could handle it.
Explicit Intents specify either the package name or a fully qualified
`ComponentName`, so the recipient is known at the time it is dispatched.
Implicit Intents can result in an unexpected (and maybe malicious) application
receiving user data. If it is possible to know the target application when
sending an Intent, always prefer using an explicit Intent.

## PendingIntents

A [PendingIntent](https://developer.android.com/reference/android/app/PendingIntent)
is created by one application and vended to another. The object allows the
receiving application to start the component (i.e. Activity, Service, Broadcast)
_as if the creating application started it_. Similar to a [setuid binary](https://en.wikipedia.org/wiki/Setuid),
you must use this with care, as it can even be used to start non-exported
components of the creating application.

It is possible to retrieve information about the creator package of the
PendingIntent using the [`getCreatorPackage()`](https://developer.android.com/reference/android/app/PendingIntent.html#getCreatorPackage())
method. This is the identity under which the Intent, which the PendingIntent
represents, will be started. Note that you cannot retrieve specific information
about the Intent (e.g. its target and extras). And as discussed above with
Intents, it is not possible to determine the application that called
`PendingIntent.send()`.

## Binder

[Binder](https://developer.android.com/reference/android/os/Binder) is the low
level IPC mechanism on Android, and it is what Intents and other Framework-level
primitives are built upon.

### Bound Services

To communicate between components using Binder, you declare a `<service>` in
your manifest and connect to it using [`Context.bindService()`](https://developer.android.com/reference/android/content/Context.html#bindService(android.content.Intent,%2520android.content.ServiceConnection,%2520int)).
This is referred to a as a [bound service](https://developer.android.com/guide/components/bound-services).

One of the powerful properties of a bound service is that you can determine the
identity of your communicating peer. This can only be done during a Binder
transaction (e.g. in an [AIDL](https://developer.android.com/guide/components/aidl)
method implementation or a [`Handler.Callback`](https://developer.android.com/reference/android/os/Handler.Callback.html))
that is **not** marked [`FLAG_ONEWAY`](https://developer.android.com/reference/android/os/IBinder).
During the transaction use [`Binder.getCallingUid()`](https://developer.android.com/reference/android/os/Binder.html#getCallingUid())
to retrieve the package's UID.

In Android, every installed application is given a unique user ID (UID). This
can be used as a key to query the [PackageManager](https://developer.android.com/reference/android/content/pm/PackageManager),
to retrieve the [PackageInfo](https://developer.android.com/reference/android/content/pm/PackageInfo)
for the application. With the PackageInfo, information about the applications
code signing certificates can be retrieved and cryptographically authenticated.
This is a strong authentication check and it is the **only** reliable mechanism
by which you can authenticate your peer.

In Chrome, the helper functions
[`ExternalAuthUtils.isCallerValid()`](https://cs.chromium.org/chromium/src/chrome/android/java/src/org/chromium/chrome/browser/externalauth/ExternalAuthUtils.java?l=157&rcl=fa790f69ce80bf2e192d710ea08b8343cad93fbb)
and `isCallerValidForPackage()` can perform these checks for you.

## Capability Tokens {#capability-tokens}

We define a **capability token** to be an unforgeable object that the holder may
present to another application as authentication to access a specific
capability. Binder objects are backed by the kernel (i.e. are unforgeable), are
transferable, and are comparable using `isEqual()`, so Binders can be used as
capability tokens.

One security factor to bear in mind is that because capability tokens are
transferable, they do not strongly authenticate a caller's identity. One
application may deliberately or accidentally transfer a capability token to
another application, or a token could be exfiltrated via an application logic
vulnerability. Therefore, only use capability tokens for access control, not
identity authentication.

While noting the above factor, capability tokens can be useful for
authenticating Intents. If two applications have established a Binder
connection, they can use the channel to exchange a capability token. One
application constructs a generic Binder (using the
[`Binder(String)`](https://developer.android.com/reference/android/os/Binder.html#Binder(java.lang.String))
constructor) and sends the object over that `ServiceConnection` to the other
application, while retaining a reference to it.

The generic Binder object can then be transmitted as an Intent extra when
sending Intents between the two applications. By comparing the object with
`Binder.isEqual()`, you can validate the capability token. Be sure to use an
[explicit Intent](#outbound-intents) when sending such an Intent.

This same approach can also be done with using a PendingIntent to a non-exported
component as a capability token. Internally PendingIntents use a Binder token
approach, so the only significant difference is the additional capability
conferred by the PendingIntent to start a component.
