blob: 8461e7c84117ce7e9c27732b7fb00cb7135b8fe7 [file] [log] [blame]
<html devsite>
<head>
<title>Policy Compatibility</title>
<meta name="project_path" value="/_project.yaml" />
<meta name="book_path" value="/_book.yaml" />
</head>
<body>
<!--
Copyright 2018 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
//www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<p>
This article describes how Android handles the policy compatibility issues
with platform OTAs, where new platform SELinux settings may differ from old vendor
SELinux settings.
</p>
<p>
Treble-based SELinux policy design considers a binary distinction
between <em>platform</em> and <em>vendor</em> policy; the scheme becomes
more complicated if vendor partitions generate dependencies, such as
<code>platform</code> &lt; <code>vendor</code> &lt; <code>oem</code>.
</p>
<p>
In Android 8.0 and higher, SELinux global policy is divided into private and
public components. Public components consist of the policy and associated
infrastructure, which are guaranteed to be available for a platform version.
This policy will be exposed to vendor policy writers to enable vendors to build
a vendor policy file, which when combined with the platform-provided policy,
results in a fully-functional policy for a device.
</p>
<ul>
<li>For versioning, the exported platform-public policy will be written as
<em>attributes</em>.</li>
<li>For ease of policy writing, exported types will be transformed into
<em>versioned attributes</em> as part of the policy build process. Public
types may also be used directly in labeling decisions provided by vendor
contexts files.</li>
</ul>
<p>
<strong>Android maintains a mapping between exported concrete types in platform
policy and the corresponding versioned attributes for each platform
version</strong>. This ensures that when objects are labeled with a type, it
does not break behavior guaranteed by the platform-public policy in a previous
version. This mapping is maintained by keeping a mapping file up-to-date for
<a href="https://android.googlesource.com/platform/system/sepolicy/+/master/prebuilts/api" class="external">
each platform version</a>, which keeps attribute membership information for each
type exported in public policy.
</p>
<h2 id="object-ownership-and-labeling">Object ownership and labeling</h2>
<p>
When customizing policy in Android 8.0 and higher, ownership must be clearly defined
for each object to keep platform and vendor policy separate. For example, if
the vendor labels <code>/dev/foo</code> and the platform then labels
<code>/dev/foo</code> in a subsequent OTA, there will be undefined behavior. For
SELinux, this manifests as a labeling collision. The device node can have only a
single label which resolves to whichever label is applied last. As a result:
</p>
<ul>
<li>Processes that <em>need access</em> to the unsuccessfully applied label will
lose access to the resource.</li>
<li>Processes that <em>gain access</em> to the file may break because the wrong
device node was created.</li>
</ul>
<p>
System properties also have potential for naming collisions that could result in
undefined behavior on the system (as well as for SELinux labeling). Collisions
between platform and vendor labels can occur for any object that has an SELinux
label, including properties, services, processes, files, and sockets. To avoid
these issues, clearly define ownership of these objects.
</p>
<p>
In addition to label collisions, SELinux type/attribute names may also collide.
A type/attribute name collision will always result in a policy compiler error.
</p>
<h3 id="type-attribute-namespacing">Type/attribute namespacing</h3>
<p>
SELinux does not allow multiple declarations of the same type/attribute. Policy
with duplicate declarations will fail to compilation. To avoid type and
attribute name collisions, all vendor declarations should be namespaced
starting with <code>np_</code>.
</p>
<pre
class="prettyprint">type foo, domain; → type np_foo, domain;</pre>
<h3 id="system-property-and-process-labeling-ownership">System property and
process labeling ownership</h3>
<p>
Avoiding labeling collisions is best solved using property namespaces. To
easily identify platform properties and avoid name conflicts when renaming or
adding exported-platform properties, ensure all vendor properties have their
own prefixes:
</p>
<table>
<tr>
<th>Property type</th>
<th>Acceptable prefixes</th>
</tr>
<tr>
<td>read-writable</td>
<td><code>vendor.</code></td>
</tr>
<tr>
<td>read-only</td>
<td><code>ro.vendor.</code><br>
<code>ro.boot.</code><br>
<code>ro.hardware.</code>
</td>
</tr>
<tr>
<td>persistent</td>
<td><code>persist.vendor.</code></td>
</tr>
</table>
<p>
Vendors can continue to use <code>ro.boot.*</code> (which comes from the kernel
cmdline) and <code>ro.hardware.*</code> (an obvious hardware-related property).
</p>
<p>
All the vendor services in init rc files should have <code>vendor.</code>
for services in init rc files of non-system partitions. Similar rules are
applied to the SELinux labels for the vendor properties (<code>vendor_</code>
for the vendor properties).
</p>
<h3 id="file-ownership">File ownership</h3>
<p>
Preventing collisions for files is challenging because platform and vendor
policy both commonly provide labels for all filesystems. Unlike type naming,
namespacing of files is not practical since many of them are created by the
kernel. To prevent these collisions, follow the naming guidance for filesystems
in this section. For Android 8.0, these are recommendations without technical
enforcement. In the future, these recommendations will be enforced by the
<a href="/compatibility/vts/">Vendor Test Suite</a> (VTS).
</p>
<h4 id="system">System (/system)</h4>
<p>
Only the system image must provide labels for <code>/system</code> components
through <code>file_contexts</code>, <code>service_contexts</code>, etc. If labels
for <code>/system</code> components are added in <code>/vendor</code> policy, a
framework-only OTA update may not be possible.
</p>
<h4 id="vendor">Vendor (/vendor)</h4>
<p>
The AOSP SELinux policy already labels parts of <code>vendor</code> partition
the platform interacts with, which enables writing SELinux rules for platform
processes to be able to talk and/or access parts of <code>vendor</code>
partition. Examples:
</p>
<table>
<tr>
<th><code>/vendor</code> path</th>
<th>Platform-provided label</th>
<th>Platform processes depending on the label</th>
</tr>
<tr>
<td><code>/vendor(/.<strong>*</strong>)?</code>
</td>
<td><code>vendor_file</code>
</td>
<td>All HAL clients in framework, <code>ueventd</code>, etc.
</td>
</tr>
<tr>
<td><code>/vendor/framework(/.<strong>*</strong>)?</code>
</td>
<td><code>vendor_framework_file</code>
</td>
<td><code>dex2oat</code>, <code>appdomain</code>, etc.
</td>
</tr>
<tr>
<td><code>/vendor/app(/.<strong>*</strong>)?</code>
</td>
<td><code>vendor_app_file</code>
</td>
<td><code>dex2oat</code>, <code>installd</code>, <code>idmap</code>, etc.
</td>
</tr>
<tr>
<td><code>/vendor/overlay(/.<strong>*</strong>)</code>
</td>
<td><code>vendor_overlay_file</code>
</td>
<td><code>system_server</code>, <code>zygote</code>, <code>idmap</code>, etc.
</td>
</tr>
</table>
<aside class="note">
<strong>*</strong> For more examples, see
<a href="https://android.googlesource.com/platform/system/sepolicy/+/master/private/file_contexts" class="external">
<code>system/sepolicy/private/file_contexts</code></a>.</aside>
<p>
As a result, specific rules must be followed (enforced through
<code>neverallows</code>) when labelling additional files in <code>vendor</code>
partition:
</p>
<ul>
<li><code>vendor_file </code>must be the default label for all files in
<code>vendor</code> partition. The platform policy requires this to access
passthrough HAL implementations.</li>
<li>All new <code>exec_types</code> added in <code>vendor</code> partition
through vendor SEPolicy must have <code>vendor_file_type</code> attribute. This
is enforced through neverallows.</li>
<li>To avoid conflicts with future platform/framework updates, avoid labelling
files other than <code>exec_types</code> in <code>vendor</code> partition.</li>
<li>All library dependencies for AOSP-identified same process HALs must be
labelled as <code>same_process_hal_file.</code></li></ul>
<h4 id="procfs">Procfs (/proc)</h4>
<p>
Files in <code>/proc</code> may be labeled using only the <code>genfscon</code>
label. In Android 7.0, both the
<a href="https://android.googlesource.com/platform/system/sepolicy/+/nougat-dr1-release/genfs_contexts" class="external">platform</a>
and <a
href="https://android.googlesource.com/device/google/marlin/+/nougat-dr1-release/sepolicy/genfs_contexts" class="external">vendor</a>
policy used <code>genfscon</code> to label files in <code>procfs</code>.
</p>
<p>
<strong>Recommendation:</strong> Only platform policy labels <code>/proc</code>.
If <code>vendor</code> processes need access to files in <code>/proc</code> that
are currently labeled with the default label (<code>proc</code>), vendor policy
should not explicitly label them and should instead use the generic
<code>proc</code> type to add rules for vendor domains. This allows the platform
updates to accommodate future kernel interfaces exposed through
<code>procfs</code> and label them explicitly as needed.
</p>
<h4 id="debugfs">Debugfs (/sys/kernel/debug)</h4>
<p>
<code>Debugfs</code> can be labeled in both <code>file_contexts</code> and
<code>genfscon</code>. In Android 7.0, both platform and vendor label
<code>debugfs</code>.
</p>
<p>
<strong>Recommendation:</strong> In the short term, only vendor policy may label
<code>debugfs</code>. In the long term, remove <code>debugfs</code>.
</p>
<h4 id="tracefs">Tracefs
(/sys/kernel/debug/tracing)</h4>
<p>
<code>Tracefs</code> can be labeled in both <code>file_contexts</code> and
<code>genfscon</code>. In Android 7.0, only the platform labels
<code>tracefs</code>.
</p>
<p>
<strong>Recommendation:</strong> Only platform may label <code>tracefs</code>.
</p>
<h4 id="sysfs">Sysfs (/sys)</h4>
<p>
Files in <code>/sys</code> may be labeled using both <code>file_contexts</code>
and <code>genfscon</code>. In Android 7.0, both platform and vendor use
<code>file_contexts</code> and <code>genfscon</code> to label files in
<code>sysfs</code>.
</p>
<p>
<strong>Recommendation:</strong> The platform may label <code>sysfs</code>
nodes that are not device-specific. Otherwise, only vendor may label files.
</p>
<h4 id="tmpfs">tmpfs (/dev)</h4>
<p>
Files in <code>/dev</code> may be labeled in <code>file_contexts</code>. In
Android 7.0, both platform and vendor label files here.
</p>
<p>
<strong>Recommendation:</strong> Vendor may label only files in
<code>/dev/vendor</code> (e.g., <code>/dev/vendor/foo</code>,
<code>/dev/vendor/socket/bar</code>).
</p>
<h4 id="rootfs">Rootfs (/)</h4>
<p>
Files in <code>/</code> may be labeled in <code>file_contexts</code>. In Android
7.0, both platform and vendor label files here.
</p>
<p>
<strong>Recommendation:</strong> Only system may label files in <code>/</code>.
</p>
<h4 id="data-data">Data (/data)</h4>
<p>
Data is labeled through a combination of <code>file_contexts</code> and
<code>seapp_contexts</code>.
</p>
<p>
<strong>Recommendation:</strong> Disallow vendor labeling outside
<code>/data/vendor</code>. Only platform may label other parts of
<code>/data</code>.
</p>
<h2 id="compatibility-attributes">Compatibility attributes</h2>
<p>
SELinux policy is an interaction between source and target types for specific
object classes and permissions. Every object (processes, files, etc.) affected
by SELinux policy may have only one type, but that type may have multiple
attributes.
</p>
<p>
Policy is written mostly in terms of existing types:
</p>
<pre
class="prettyprint">allow source_type target_type:target_class permission(s);</pre>
<p>
This works because the policy was written with knowledge of all types. However,
if the vendor policy and platform policy use specific types, and the label of a
specific object changes in only one of those policies, the other may contain
policy that gained or lost access previously relied upon. For example:
</p>
<pre class="prettyprint">File_contexts:
/sys/A u:object_r:sysfs:s0
Platform: allow p_domain sysfs:class perm;
Vendor: allow v_domain sysfs:class perm;</pre>
<p>
Could be changed to:
</p>
<pre class="prettyprint">File_contexts:
/sys/A u:object_r:sysfs_A:s0</pre>
<p>
Although the vendor policy would remain the same, the <code>v_domain</code>
would lose access due to the lack of policy for the new <code>sysfs_A</code>
type.
</p>
<p>
By defining a policy in terms of attributes, we can give the underlying object a
type that has an attribute corresponding to policy for both the platform and
vendor code. This can be done for all types to effectively create an
<em>attribute-policy</em> wherein concrete types are never used. In practice,
this is required only for the portions of policy that overlap between platform
and vendor, which are defined and provided as <em>platform public policy</em>
that gets built as part of the vendor policy.
</p>
<p>
Defining public policy as versioned attributes satisfies two policy
compatibility goals:
</p>
<ul>
<li><strong>Ensure vendor code continues to work after platform update</strong>.
Achieved by adding attributes to concrete types for objects corresponding to
those on which vendor code relied, preserving access.</li>
<li><strong>Ability to deprecate policy</strong>. Achieved by clearly
delineating policy sets into attributes that can be removed as soon as the
version to which they correspond no longer is supported. Development can
continue in the platform, knowing the old policy is still present in the
vendor policy and will be automatically removed when/if it upgrades.</li>
</ul>
<h3 id="policy-writability">Policy writability</h3>
<p>
To meet the goal of not requiring knowledge of specific version changes for
policy development, Android 8.0 includes a mapping between platform-public
policy types and their attributes. Type <code>foo</code> is mapped
to attribute <code>foo_v<em>N</em></code>, where <code><em>N</em></code> is the
version targeted. <code>vN</code> corresponds to the
<code>PLATFORM_SEPOLICY_VERSION</code> build variable and is of the form
<code>MM.NN</code>, where <code>MM</code> corresponds to the platform SDK number
and <code>NN</code> is a platform sepolicy specific version.
</p>
<p>
Attributes in public policy are not versioned, but rather exist as an API on
which platform and vendor policy can build to keep the interface between the two
partitions stable. Both platform and vendor policy writers can continue to write
policy as it is written today.
</p>
<p>
Platform-public policy exported as <code>allow source_foo target_bar:<em>class
perm</em>;</code>is included as part of the vendor policy. During
<a href="/security/selinux/build">compilation</a> (which includes the
corresponding version) it is transformed into the policy that will go to the
vendor portion of the device (shown in the transformed Common Intermediate
Language (CIL)):
</p>
<pre
class="prettyprint"> (allow source_foo_vN target_bar_vN (class (perm)))</pre>
<p>
As vendor policy is never ahead of the platform, it should not be concerned with
prior versions. However, platform policy will need to know how far back vendor
policy is, include attributes to its types, and set policy corresponding to
versioned attributes.
</p>
<h3 id="policy-diffs">Policy diffs</h3>
<p>
Automatically creating attributes by adding <code>_v<em>N</em></code> to the end
of each type does nothing without mapping of attributes to types across version
diffs. Android maintains a mapping between versions for attributes and a
mapping of types to those attributes. This is done in the aforementioned mapping
files with statements, such as (CIL):
</p>
<pre class="prettyprint">(typeattributeset foo_vN (foo))</pre>
<h4 id="platform-upgrades">Platform upgrades</h4>
<p>
The following section details scenarios for platform upgrades.
</p>
<h5 id="same-types">Same types</h5>
<p>
This scenario occurs when an object does not change labels in policy versions.
This is the same for source and target types and can be seen with
<code>/dev/binder</code>, which is labeled <code>binder_device</code> across all
releases. It is represented in transformed policy as:
</p>
<pre class="prettyprint">binder_device_v1 … binder_device_vN</pre>
<p>
When upgrading from <code>v1</code><code>v2</code>, the platform policy must
contain:
</p>
<pre
class="prettyprint">type binder_device; -&gt; (type binder_device) (in CIL)</pre>
<p>
In the v1 mapping file (CIL):
</p>
<pre
class="prettyprint">(typeattributeset binder_device_v1 (binder_device))</pre>
<p>
In the v2 mapping file (CIL):
</p>
<pre
class="prettyprint">(typeattributeset binder_device_v2 (binder_device))</pre>
<p>
In the v1 vendor policy (CIL):
</p>
<pre class="prettyprint">(typeattribute binder_device_v1)
(allow binder_device_v1 …)</pre>
<p>
In the v2 vendor policy (CIL):
</p>
<pre class="prettyprint">(typeattribute binder_device_v2)
(allow binder_device_v2 …)</pre>
<h5 id="new-types">New types</h5>
<p>
This scenario occurs when the platform has added a new type, which can happen
when adding new features or during policy hardening.
</p>
<ul>
<li><strong>New feature</strong>. When the type is labeling an object that was
previously non-existent (such as a new service process), the vendor code did not
previously interact with it directly so no corresponding policy exists. The new
attribute corresponding to the type does not have an attribute in the previous
version, and so would not need an entry in the mapping file targeting that
version.</li>
<li><strong>Policy hardening</strong>. When the type represents policy
hardening, the new type attribute must link back to a chain of attributes
corresponding to the previous one (similar to the previous example changing
<code>/sys/A</code> from <code>sysfs</code> to <code>sysfs_A</code>). Vendor
code relies on a rule enabling access to <code>sysfs</code>, and needs
to include that rule as an attribute of the new type.</li>
</ul>
<p>
When upgrading from <code>v1</code><code>v2</code>, the platform policy must
contain:
</p>
<pre
class="prettyprint">type sysfs_A; -&gt; (type sysfs_A) (in CIL)
type sysfs; (type sysfs) (in CIL)</pre>
<p>
In the v1 mapping file (CIL):
</p>
<pre
class="prettyprint">(typeattributeset sysfs_v1 (sysfs sysfs_A))</pre>
<p>
In the v2 mapping file (CIL):
</p>
<pre class="prettyprint">(typeattributeset sysfs_v2 (sysfs))
(typeattributeset sysfs_A_v2 (sysfs_A))</pre>
<p>
In the v1 vendor policy (CIL):
</p>
<pre class="prettyprint">(typeattribute sysfs_v1)
(allow … sysfs_v1 …)</pre>
<p>
In the v2 vendor policy (CIL):
</p>
<pre class="prettyprint">(typeattribute sysfs_A_v2)
(allow … sysfs_A_v2 …)
(typeattribute sysfs_v2)
(allow … sysfs_v2 …)</pre>
</li></ul>
<h5 id="removed-types">Removed types</h5>
<p>
This (rare) scenario occurs when a type is removed, which can happen when the
underlying object:
</p>
<ul>
<li>Remains but gets a different label.</li>
<li>Is removed by the platform.</li>
</ul>
<p>
During policy loosening, a type is removed and the object labeled with that type
is given a different, already-existing label. This represents a merging of
attribute mappings: The vendor code must still be able to access the underlying
object by the attribute it used to possess, but the rest of the system must now
be able to access it with its new attribute.
</p>
<p>
If the attribute to which it has been switched is new, then relabeling is the
same as in the new type case, except that when an existing label is used, the
addition of the old attribute new type would cause other objects also labeled
with this type to be newly accessible. This is essentially what is done by the
platform and is deemed to be an acceptable tradeoff to maintain
compatibility.
</p>
<pre class="prettyprint">(typeattribute sysfs_v1)
(allow … sysfs_v1 …)</pre>
<p>
<strong>Example Version 1: Collapsing types (removing sysfs_A)</strong>
</p>
<p>
When upgrading from <code>v1</code><code>v2</code>, the platform policy must
contain:
</p>
<pre
class="prettyprint">type sysfs; (type sysfs) (in CIL)</pre>
<p>
In the v1 mapping file (CIL):
</p>
<pre class="prettyprint">(typeattributeset sysfs_v1 (sysfs))
(type sysfs_A) # in case vendors used the sysfs_A label on objects
(typeattributeset sysfs_A_v1 (sysfs sysfs_A))</pre>
<p>
In the v2 mapping file (CIL):
</p>
<pre class="prettyprint">(typeattributeset sysfs_v2 (sysfs))</pre>
<p>
In the v1 vendor policy (CIL):
</p>
<pre class="prettyprint">(typeattribute sysfs_A_v1)
(allow … sysfs_A_v1 …)
(typeattribute sysfs_v1)
(allow … sysfs_v1 …)</pre>
<p>
In the v2 vendor policy (CIL):
</p>
<pre class="prettyprint">(typeattribute sysfs_v2)
(allow … sysfs_v2 …)</pre>
<p>
<strong>Example Version 2: Removing completely (foo type)</strong>
</p>
<p>
When upgrading from <code>v1</code><code>v2</code>, the platform policy must
contain:
</p>
<pre
class="prettyprint"># nothing - we got rid of the type</pre>
<p>
In the v1 mapping file (CIL):
</p>
<pre
class="prettyprint">(type foo) #needed in case vendors used the foo label on objects
(typeattributeset foo_v1 (foo))</pre>
<p>
In the v2 mapping file (CIL):
</p>
<pre
class="prettyprint"># nothing - get rid of it</pre>
<p>
In the v1 vendor policy (CIL):
</p>
<pre class="prettyprint">(typeattribute foo_v1)
(allow foo …)
(typeattribute sysfs_v1)
(allow sysfs_v1 …)</pre>
<p>
In the v2 vendor policy (CIL):
</p>
<pre class="prettyprint">(typeattribute sysfs_v2)
(allow sysfs_v2 …)</pre>
<h5 id="new-class-permissions">New class/permissions</h5>
<p>
This scenario occurs when a platform upgrade introduces new policy components
that do not exist in previous versions. For example, when Android added the
<code>servicemanager</code> object manager that created the add, find, and list
permissions, vendor daemons wanting to register with the
<code>servicemanager</code> needed permissions that were not
available. In Android 8.0, only the platform policy may add new classes and
permissions.
</p>
<p>
To allow all domains that could have been created or extended by vendor policy
to use the new class without obstruction, the platform policy needs to include a
rule similar to:
</p>
<pre
class="prettyprint">allow {domain -coredomain} *:new_class perm;</pre>
<p>
This may even require policy allowing access for all interface (public policy)
types, to be sure vendor image gains access. If this results in unacceptable
security policy (as it may have with the servicemanager changes), a vendor
upgrade could potentially be forced.
</p>
<h5 id="removed-class-permissions">Removed class/permissions</h5>
<p>
This scenario occurs when an object manager is removed (such as the
<code>ZygoteConnection</code> object manager) and should not cause issues. The
object manager class and permissions could remain defined in policy until the
vendor version no longer uses it. This is done by adding the definitions
to the corresponding mapping file.
</p>
<h4 id="vendor-customization-for-new-relabeled-types">Vendor customization for
new/relabeled types</h4>
<p>
New vendor types are at the core of vendor policy development as they are needed
to describe new processes, binaries, devices, subsystems, and stored data. As
such, it is imperative to allow the creation of vendor-defined types.
</p>
<p>
As vendor policy is always the oldest on the device, there is no need to
automatically convert all vendor types to attributes in policy. The platform
does not rely on anything labeled in vendor policy because the platform has no
knowledge of it; however, the platform will provide the attributes and public
types it uses to interact with objects labeled with these types (such as
<code>domain</code>, <code>sysfs_type</code>, etc.). For the platform to
continue to interact correctly with these objects, the attributes and types
must be appropriately applied and specific rules may need to be added to the
customizable domains (such as <code>init</code>).
</p>
<h2 id="attributes-p">Attribute changes for Android 9</h2>
<p>
Devices upgrading to Android 9 can use the following attributes, but devices
launching with Android 9 must not.
</p>
<h3 id="violator-attributes">Violator attributes</h3>
<p>
Android 9 includes these domain-related attributes:
</p>
<ul>
<li><strong><code>data_between_core_and_vendor_violators</code></strong>.
Attribute for all domains that violate the requirement of not sharing files by
path between <code>vendor</code> and <code>coredomains</code>. Platform and
vendor processes shouldn't use on-disk files to communicate (unstable ABI).
Recommendation:
<ul>
<li>Vendor code should use <code>/data/vendor</code>.</li>
<li>System should not use <code>/data/vendor</code>.</li>
</ul
</li>
<li><strong><code>system_executes_vendor_violators</code></strong>. Attribute
for all system domains (except <code>init</code> and <code>shell domains</code>)
that violate the requirement of not executing vendor binaries. Execution of
vendor binaries has unstable API. Platform shouldn't execute vendor binaries
directly. Recommendation:
<ul>
<li>Such platform dependencies on vendor binaries must be behind HIDL HALs.
<p> <strong><em>OR</em></strong></p></li>
<li><code>coredomains</code> that need access to vendor binaries should be
moved to the vendor partition and thus, stop being <code>coredomain</code>.</li>
</ul>
</li>
</ul>
<h3 id="untrusted-attributes">Untrusted attributes</h3>
<p>
Untrusted apps that host arbitrary code shouldn't have access to HwBinder
services, except those considered sufficiently safe for access from such apps
(see safe services below). The two main reasons for this are:
</p>
<ol>
<li>HwBinder servers do not perform client authentication because HIDL currently
does not expose caller UID information. Even if HIDL did expose such data, many
HwBinder services either operate at a level below that of apps (such as, HALs) or
must not rely on app identity for authorization. Thus, to be safe, the default
assumption is that every HwBinder service treats all its clients as equally
authorized to perform operations offered by the service.</li>
<li>HAL servers (a subset of HwBinder services) contain code with higher
incidence rate of security issues than <code>system/core</code> components and
have access to the lower layers of the stack (all the way down to hardware) thus
increasing opportunities for bypassing the Android security model.</li></ol>
<h4 id="safe-services">Safe services</h4>
<p>
Safe services include:
</p>
<ul>
<li><code>same_process_hwservice</code>. These services (by definition) run in
the process of the client and thus have the same access as the client domain in
which the process runs.</li>
<li><code>coredomain_hwservice</code>. These services do not pose risks
associated with reason #2.</li>
<li><code>hal_configstore_ISurfaceFlingerConfigs</code>. This service is
specifically designed for use by any domain.</li>
<li><code>hal_graphics_allocator_hwservice</code>. These operations are also
offered by <code>surfaceflinger</code> Binder service, which apps are permitted
to access.</li>
<li><code>hal_omx_hwservice</code>. This is a HwBinder version of the
<code>mediacodec</code> Binder service, which apps are permitted to access.</li>
<li><code>hal_codec2_hwservice</code>. This is a newer version of
<code>hal_omx_hwservice</code>.</li>
</ul>
<h4 id="useable-attributes">Useable attributes</h4>
<p>
All <code>hwservices</code> not considered safe have the attribute
<code>untrusted_app_visible_hwservice</code>. The corresponding HAL servers have
the attribute <code>untrusted_app_visible_halserver</code>. Devices launching
with Android P MUST NOT use either <code>untrusted</code> attribute.
</p>
<p>
Recommendation:
</p>
<ul>
<li>Untrusted apps should instead talk to a system service that talks to the
vendor HIDL HAL. For example, apps can talk to <code><a
href="https://android.googlesource.com/platform/system/sepolicy/+/master/public/app.te#209"
class="external">binderservicedomain</a></code>, then <code>mediaserver</code>
(which is a <code>binderservicedomain</code>) in turn talks to the <code><a
href="https://android.googlesource.com/platform/system/sepolicy/+/master/private/mediaserver.te#6"
class="external">hal_graphics_allocator</a></code>.
<p><strong><em>OR</em></strong></p></li>
<li>Apps that need direct access to <code>vendor</code> HALs should have their
own vendor-defined sepolicy domain.</li>
</ul>
<h3 id="file-attribute-tests">File attribute tests</h3>
<p>
Android 9 includes <a
href="https://android.googlesource.com/platform/system/sepolicy/+/master/tests/sepolicy_tests.py"
class="external">build time tests</a> that ensure all files in specific
locations have the appropriate attributes (such as, all files in
<code>sysfs</code> have the required <code>sysfs_type</code> attribute).
</p>
<h2 id="platform-public-policy">Platform-public policy</h2>
<p>
The platform-public policy is the core of conforming to the Android 8.0
architecture model without simply maintaining the union of platform policies
from v1 and v2. Vendors are exposed to a subset of platform policy that
contains useable types and attributes and rules on those types and attributes
which then becomes part of vendor policy (i.e.
<code>vendor_sepolicy.cil</code>).
</p>
<p>
Types and rules are automatically translated in the vendor-generated policy
into <code>attribute_v<em>N</em></code> such that all platform-provided types
are versioned attributes (however attributes are not versioned). The platform is
responsible for mapping the concrete types it provides into the appropriate
attributes to ensure that vendor policy continues to function and that the rules
provided for a particular version are included. The combination of
platform-public policy and vendor policy satisfies the Android 8.0 architecture
model goal of allowing independent platform and vendor builds.
</p>
<h3 id="mapping-to-attribute-chains">Mapping to attribute chains</h3>
<p>
When using attributes to map to policy versions, a type maps to an attribute or
multiple attributes, ensuring objects labeled with the type are accessible via
attributes corresponding to their previous types.
</p>
<p>
Maintaining a goal to hide version information from the policy writer means
automatically generating the versioned attributes and assigning them to the
appropriate types. In the common case of static types, this is straightforward:
<code>type_foo</code> maps to <code>type_foo_v1</code>.
</p>
<p>
For an object label change such as <code>sysfs</code><code>sysfs_A</code> or
<code>mediaserver</code><code>audioserver</code>, creating this mapping is
non-trivial (and is described in the examples above). Platform policy maintainers
must determine how to create the mapping at transition points for objects, which
requires understanding the relationship between objects and their assigned
labels and determining when this occurs. For backwards compatibility, this
complexity needs to be managed on the platform side, which is the only partition
that may uprev.
</p>
<h3 id="version-uprevs">Version uprevs</h3>
<p>
For simplicity, the Android platform releases an sepolicy version when a new
release branch is cut. As described above, the version number is contained in
<code>PLATFORM_SEPOLICY_VERSION</code> and is of the form <code>MM.nn</code>,
where <code>MM</code> corresponds to the SDK value and <code>nn</code> is a
private value maintained in<code> /platform/system/sepolicy.</code> For
example, <code>19.0</code> for Kitkat, <code>21.0</code> for Lollipop,
<code>22.0</code> for Lollipop-MR1 <code>23.0</code> for Marshmallow,
<code>24.0</code> for Nougat, <code>25.0</code> for Nougat-MR1,
<code>26.0</code> for Oreo, <code>27.0</code> for Oreo-MR1, and
<code>28.0</code> for Android P. Uprevs aren't always whole numbers. For
example, if an MR bump to a versions necessitates an incompatible change in
<code>system/sepolicy/public</code> but not an API bump, then that sepolicy
version could be: <code>vN.1</code>. The version present in a development
branch is a never-to-be-used-in-shipping-devices <code>10000.0</code>.
</p>
<p>
Android may deprecate oldest version when upreving. For input on when to
deprecate a version, Android may collect the number of devices with vendor
policies running that Android version and still receiving major platform
updates. If the number is less than a certain threshold, that version is
deprecated.
</p>
<h3 id="performance-impact-of-multiple-attributes">Performance impact of
multiple attributes</h3>
<p>
As described in <a
href="https://github.com/SELinuxProject/cil/issues/9" class="external">https://github.com/SELinuxProject/cil/issues/9</a>,
a large number of attributes assigned to a type result in performance issues in
the event of a policy cache miss.
</p>
<p>
This was confirmed to be an issue in Android, so <a
href="http://marc.info/?l=selinux&m=149202161421482&w=2" class="external">changes
were made</a> to Android 8.0 to remove attributes added to the policy by the
policy compiler, as well as to remove unused attributes. These changes resolved
performance regressions.
</p>
<h2 id="selinux-contexts-labeling">SELinux contexts labeling</h2>
<p>To support the distinction between platform and vendor sepolicy,
the system builds SELinux context files differently to keep them separate.
</p>
<h3 id="file-contexts">File contexts</h3>
<p>
Android 8.0 introduced the following changes for <code>file_contexts</code>:
</p>
<ul>
<li>To avoid additional compilation overhead on device during boot,
<code>file_contexts</code> cease to exist in the binary form. Instead, they
are readable, regular expression text file such as <code>{property,
service}_contexts</code> (as they were pre-7.0).</li>
<li>The <code>file_contexts</code> are split between two files:
<ul>
<li><code>plat_file_contexts</code>
<ul>
<li>Android platform <code>file_context</code> that has no
device-specific labels, except for labeling parts of
<code>/vendor</code> partition that must be labeled precisely to
ensure proper functioning of the sepolicy files.</li>
<li>Must reside in <code>system</code> partition at
<code>/system/etc/selinux/plat_file_contexts</code> on device and
be loaded by <code>init</code> at the start along with the
vendor <code>file_context</code>.</li>
</ul>
</li>
<li><code>vendor_file_contexts</code>
<ul>
<li>Device-specific <code>file_context</code> built by combining
<code>file_contexts</code> found in the directories pointed to by
<code>BOARD_SEPOLICY_DIRS</code> in the device's
<code>Boardconfig.mk</code> files.</li>
<li>Must be installed at
<code>/vendor/etc/selinux/vendor_file_contexts</code> in
<code>vendor</code> partition and be loaded by <code>init</code> at
the start along with the platform <code>file_context</code>.</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="property-contexts">Property contexts</h3>
<p>
In Android 8.0, the <code>property_contexts</code> is split between two files:
</p>
<ul>
<li><code>plat_property_contexts</code>
<ul>
<li>Android platform <code>property_context</code> that has no
device-specific labels.</li>
<li>Must reside in <code>system</code> partition at
<code>/system/etc/selinux/plat_property_contexts</code> and be loaded
by <code>init</code> at the start along with the vendor
<code>property_contexts</code>.</li>
</ul>
</li>
<li><code>vendor_property_contexts</code>
<ul>
<li>Device-specific <code>property_context</code> built by combining
<code>property_contexts</code> found in the directories pointed to by
<code>BOARD_SEPOLICY_DIRS</code> in device's
<code>Boardconfig.mk</code> files.</li>
<li>Must reside in <code>vendor</code> partition at
<code>/vendor/etc/selinux/vendor_property_contexts</code> and be
loaded by <code>init</code> at the start along with the platform
<code>property_context</code></li>
</ul>
</li>
</ul>
<h3 id="service-contexts">Service contexts</h3>
<p>
In Android 8.0, the <code>service_contexts</code> is split between the following
files:
</p>
<ul>
<li><code>plat_service_contexts</code>
<ul>
<li>Android platform-specific <code>service_context</code> for the
<code>servicemanager</code>. The <code>service_context</code> has no
device-specific labels.</li>
<li>Must reside in <code>system</code> partition at
<code>/system/etc/selinux/plat_service_contexts</code> and be loaded by
<code>servicemanager</code> at the start along with the vendor
<code>service_contexts</code>.</li>
</ul>
</li>
<li><code>vendor_service_contexts</code>
<ul>
<li>Device-specific <code>service_context</code> built by combining
<code>service_contexts</code> found in the directories pointed to by
<code>BOARD_SEPOLICY_DIRS</code> in the device's
<code>Boardconfig.mk</code> files.</li>
<li>Must reside in <code>vendor</code> partition at
<code>/vendor/etc/selinux/vendor_service_contexts</code> and be loaded
by <code>servicemanager</code> at the start along with the platform
<code>service_contexts</code>.</li>
<li>Although <code>servicemanager</code> looks for this file at boot time,
for a fully compliant <code>TREBLE</code> device, the
<code>vendor_service_contexts</code> MUST NOT exist. This is because
all interaction between <code>vendor</code> and <code>system</code>
processes MUST go through
<code>hwservicemanager</code>/<code>hwbinder</code>.</li>
</ul>
</li>
<li><code>plat_hwservice_contexts</code>
<ul>
<li>Android platform <code>hwservice_context</code> for
<code>hwservicemanager</code> that has no device-specific labels.</li>
<li>Must reside in <code>system</code> partition at
<code>/system/etc/selinux/plat_hwservice_contexts</code> and be loaded by
<code>hwservicemanager</code> at the start along with the
<code>vendor_hwservice_contexts</code>.</li>
</ul>
</li>
<li><code>vendor_hwservice_contexts</code>
<ul>
<li>Device-specific <code>hwservice_context</code> built by combining
<code>hwservice_contexts</code> found in the directories pointed to by
<code>BOARD_SEPOLICY_DIRS</code> in the device's
<code>Boardconfig.mk</code> files.</li>
<li>Must reside in <code>vendor</code> partition at
<code>/vendor/etc/selinux/vendor_hwservice_contexts</code> and be
loaded by <code>hwservicemanager</code> at the start along with the
<code>plat_service_contexts</code>.</li>
</ul>
</li>
<li><code>vndservice_contexts</code>
<ul>
<li>Device-specific <code>service_context</code> for the
<code>vndservicemanager</code> built by combining
<code>vndservice_contexts</code> found in the directories pointed to by
<code>BOARD_SEPOLICY_DIRS</code> in the device's
<code>Boardconfig.mk</code>.</li>
<li>This file must reside in <code>vendor</code> partition at
<code>/vendor/etc/selinux/vndservice_contexts</code> and be loaded by
<code>vndservicemanager</code> at the start.</li>
</ul>
</li>
</ul>
<h3 id="seapp-contexts">Seapp contexts</h3>
<p>
In Android 8.0, the <code>seapp_contexts</code> is split between two files:
</p>
<ul>
<li><code>plat_seapp_contexts</code>
<ul>
<li>Android platform <code>seapp_context</code> that has no device-specific
changes.</li>
<li>Must reside in <code>system</code> partition at
<code>/system/etc/selinux/plat_seapp_contexts.</code></li>
</ul>
</li>
<li><code>vendor_seapp_contexts</code>
<ul>
<li>Device-specific extension to platform <code>seapp_context</code> built
by combining <code>seapp_contexts</code> found in the directories
pointed to by <code>BOARD_SEPOLICY_DIRS</code> in the device's
<code>Boardconfig.mk</code> files.</li>
<li>Must reside in <code>vendor</code> partition at
<code>/vendor/etc/selinux/vendor_seapp_contexts</code>.</li>
</ul>
</li>
</ul>
<h3 id="mac-permissions">MAC permissions</h3>
<p>
In Android 8.0, the <code>mac_permissions.xml</code> is split between two files:
</p>
<ul>
<li>Platform <code>mac_permissions.xml</code>
<ul>
<li>Android platform <code>mac_permissions.xml</code> that has no
device-specific changes.</li>
<li>Must reside in <code>system</code> partition at
<code>/system/etc/selinux/.</code></li>
</ul>
</li>
<li>Non-Platform <code>mac_permissions.xml</code>
<ul>
<li>Device-specific extension to platform
<code>mac_permissions.xml</code> built from
<code>mac_permissions.xml</code> found in the directories pointed to by
<code>BOARD_SEPOLICY_DIRS</code> in the device's
<code>Boardconfig.mk</code> files.</li>
<li>Must reside in <code>vendor</code> partition at
<code>/vendor/etc/selinux/.</code></li>
</ul>
</li>
</ul>
</body>
</html>