blob: 829384719a73f8f95799dd5da1c9e464bb634442 [file] [log] [blame]
page.title=Writing SELinux Policy
@jd:body
<!--
Copyright 2014 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
http://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.
-->
<div id="qv-wrapper">
<div id="qv">
<h2>In this document</h2>
<ol id="auto-toc">
</ol>
</div>
</div>
<p>The Android Open Source Project (AOSP) provides a solid base policy for the
applications and services that are common across all Android devices.
Contributors to AOSP regularly refine this policy. The core policy is expected
to make up about 90&ndash;95% of the final on-device policy with device-specific
customizations making up the remaining 5&ndash;10%. This article focuses on these
device-specific customizations, how to write device-specific policy, and some
of the pitfalls to avoid along the way.</p>
<h2 id=device_bringup>Device bringup</h2>
<p>While writing device-specific policy, progress through the following steps in order.</p>
<h3 id=run_in_permissive_mode>Run in permissive mode</h3>
<p>When a device is in <a href="index.html#background">permissive mode</a>,
denials are logged but not enforced. Permissive mode is important for two
reasons:</p>
<ol>
<li> Permissive mode ensures that policy bringup does not delay other early device
bringup tasks.
<li> An enforced denial may mask other denials. For example, file access
typically entails a directory search, file open, then file read. In
enforcing mode, only the directory search denial would occur. Permissive
mode ensures all denials are seen.
</ol>
<p>The simplest way to put a device into permissive mode is via the
<a href="validate.html#switching_to_permissive">kernel command line</a>. This
can be added to the the device’s BoardConfig.mk file:
<code>platform/device/&lt;vendor&gt;/&lt;target&gt;/BoardConfig.mk</code>.
After modifying the command line, perform <code>make clean</code>, then
<code>make bootimage</code>, and flash the new boot image.</p>
<p>After that, confirm permissive mode with:</p>
<p><code>adb getenforce</code></p>
<p>Two weeks is a reasonable amount of time to be in global permissive mode. After
addressing the majority of denials, move back into enforcing mode and address
bugs as they come in. Domains still producing denials or services still under
heavy development can be temporarily put into permissive mode, but move them
back to enforcing mode as soon as possible.</p>
<h3 id=enforce_early>Enforce early</h3>
<p>In enforcing mode, denials are both logged and enforced. It is a best practice
to get your device into enforcing mode as early as possible. Waiting to create
and enforce device-specific policy often results in a buggy product and a bad
user experience. Start early enough to participate in
<a href="https://en.wikipedia.org/wiki/Eating_your_own_dog_food">dogfooding</a>
and ensure full test coverage of functionality in real world usage. Starting
early ensures security concerns inform design decisions. Conversely, granting
permissions based solely on observed denials is an unsafe approach. Use this
time to perform a security audit of the device and file bugs against behavior
that should not be allowed.</p>
<h3 id=remove_or_delete_existing_policy>Remove or delete existing policy</h3>
<p>There are a number of good reasons to create device-specific policy from
scratch on a new device, which include:</p>
<ul>
<li> Security auditing
<li> <a href="#overuse_of_negation">Overly permissive policy</a>
<li> <a href="#policy_size_explosion">Policy size reduction</a>
<li> Dead policy
</ul>
<h3 id=address_denials_of_core_services>Address denials of core services</h3>
<p>Denials generated by core services are typically addressed by file labeling.
For example:</p>
<pre class="no-pretty-print">
avc: denied { open } for pid=1003 comm=”mediaserver” path="/dev/kgsl-3d0”
dev="tmpfs" scontext=u:r:mediaserver:s0 tcontext=u:object_r:device:s0
tclass=chr_file permissive=1
avc: denied { read write } for pid=1003 name="kgsl-3d0" dev="tmpfs"
scontext=u:r:mediaserver:s0
tcontext=u:object_r:device:s0 tclass=chr_file permissive=1
</pre>
<p>is completely addressed by properly labeling <code>/dev/kgsl-3d0</code>. In
this example, <code>tcontext</code> is <code>device</code>. This represents a
default context where everything in <code>/dev</code> receives the
<a href="https://android.googlesource.com/platform/external/sepolicy/+/marshmallow-dev/file_contexts#31">
device</a>” label unless a more specific label is assigned. Simply accepting
the output from <a href="validate.html#using_audit2allow">audit2allow</a> here
would result in an incorrect and overly permissive rule.</p>
<p>To solve this kind of problem, give the file a more specific label, which in
this case is
<a href="https://android.googlesource.com/device/lge/hammerhead/+/marshmallow-dev/sepolicy/file_contexts#1">
gpu_device</a>. No further permissions are needed as the
<a href="https://android.googlesource.com/platform/external/sepolicy/+/marshmallow-dev/mediaserver.te#24">
mediaserver already has necessary permissions</a> in core policy to access the
gpu_device.</p>
<p>Other device-specific files that should be labeled with types predefined in
core policy:</p>
<ol>
<li> <a href="https://android.googlesource.com/device/lge/hammerhead/+/marshmallow-dev/sepolicy/file_contexts#31">
block devices</a>
<li> <a href="https://android.googlesource.com/device/lge/hammerhead/+/marshmallow-dev/sepolicy/file_contexts#80">
audio devices</a>
<li> <a href="https://android.googlesource.com/device/lge/hammerhead/+/marshmallow-dev/sepolicy/file_contexts#21">
video devices</a>
<li> <a href="https://android.googlesource.com/device/lge/hammerhead/+/marshmallow-dev/sepolicy/file_contexts#89">
sensors</a>
<li> <a href="https://android.googlesource.com/device/lge/hammerhead/+/marshmallow-dev/sepolicy/file_contexts#8">
nfc</a>
<li> gps_device
<li> <a href="https://android.googlesource.com/device/lge/hammerhead/+/marshmallow-dev/sepolicy/file_contexts#139">
files in /sys</a>
<li> files in /proc
</ol>
<p>In general, granting permissions to default labels is wrong. Many of these
permissions are disallowed by <a href="customize.html#neverallow">neverallow</a>
rules, but even when not explicitly disallowed, best practice is to provide a
specific label.</p>
<h3 id=label_new_services_and_address_denials>Label new services and address denials</h3>
<p>Init-launched services are required to run in their own SELinux domains. The
following example puts service “foo” into its own SELinux domain and grants it
permissions.</p>
<p>The service is launched in our device’s <code>init.&lt;target&gt;.rc</code> file as:</p>
<pre class="no-pretty-print">
service foo /system/bin/foo
class core
</pre>
<ol>
<li>Create a new domain "foo"<br />
<p>Create the file <code>device/&lt;oem&gt;/&lt;target&gt;/sepolicy/foo.te</code>
with the following contents:</p>
<pre class="no-pretty-print">
# foo service
type foo, domain;
type foo_exec, exec_type, file_type;
init_daemon_domain(foo)
</pre>
<p>This is the initial template for the foo SELinux domain, to which you
can add rules based on the specific operations performed by that executable.</p>
</li>
<li>Label <code>/system/bin/foo</code><br />
<p>Add the following to <code>device/&lt;oem&gt;/&lt;target&gt;/sepolicy/
file_contexts</code>:</p>
<pre class="no-pretty-print">
/system/bin/foo u:object_r:foo_exec:s0
</pre>
<p>This makes sure the executable is properly labeled so SELinux runs the
service in the proper domain.</p>
</li>
<li>Build and flash the boot and system images.</li>
<li>Refine the SELinux rules for the domain.<br />
<p>Use denials to determine the required permissions. The
<a href="validate.html#using_audit2allow">audit2allow</a> tool provides
good guidelines, but only use it to inform policy writing. Do
not just copy the output.</p>
</li>
</ol>
<h3 id=enforcing_mode>Switch back to enforcing mode</h3>
<p>It’s fine to troubleshoot in permissive mode, but switch back to enforcing
mode as early as possible and try to remain there.</p>
<h2 id=common_mistakes>Common mistakes</h2>
<p>Here are a few solutions for common mistakes that happen when writing
device-specific policies.</p>
<h3 id=overuse_of_negation>Overuse of negation</h3>
<p>The following example rule is like locking the front door but leaving the
windows open:</p>
<p><code>allow { domain -untrusted_app } scary_debug_device:chr_file rw_file_perms</code>.</p>
<p>The intent is clear: everyone but third-party apps may have access to the debug
device. </p>
<p>The rule is flawed in a few of ways. The exclusion of <code>untrusted_app</code>
is trivial to work around because all apps may optionally run services in the
<code>isolated_app</code> domain. Likewise, if new domains for third-party apps
are added to AOSP, they will also have access to <code>scary_debug_device</code>.
The rule is overly permissive. Most domains will not benefit from having
access to this debugging tool. The rule should have been written to allow only
the domains that require access. </p>
<h3 id=debugging_features_in_production>Debugging features in production</h3>
<p>Debug features should not be present on production builds nor should their
policy.</p>
<p>The simplest alternative is to only allow the debug feature when SELinux is
disabled on eng/userdebug builds, such as <code>adb root</code> and
<code>adb setenforce 0</code>.</p>
<p>Another safe alternative is to enclose debug permissions in a
<a href="https://android.googlesource.com/device/lge/hammerhead/+/marshmallow-dev/sepolicy/platform_app.te#3">
userdebug_or_eng</a> statement.</p>
<h3 id=policy_size_explosion>Policy size explosion</h3>
<p><a href="http://arxiv.org/abs/1510.05497">Characterizing SEAndroid Policies in the Wild</a>
describes a concerning trend in the growth of device policy customizations.
Device-specific policy should account for 5&ndash;10% of the overall policy running on
a device. Customizations in the 20%+ range almost certainly contain over
privileged domains and dead policy.</p>
<p>Unnecessarily large policy:</p>
<ul>
<li> Takes a double hit on memory as the policy sits in the ramdisk and is also
loaded into kernel memory.
<li> Wastes disk space by necessitating a larger bootimage.
<li> Affects runtime policy lookup times.
</ul>
<p> The following example shows two devices where the manufacturer-specific policy
comprised 50% and 40% of the on-device policy. A rewrite of the policy yielded
substantial security improvements with no loss in functionality, as shown
below. (AOSP devices Shamu and Flounder are included for comparison.)</p>
<p><img alt="Figure 1: Comparison of device-specific policy size after security audit."
src="images/selinux_device_policy_reduction.png" /></p>
<p class="img-caption"><strong>Figure 1</strong>. Comparison of device-specific
policy size after security audit.</p>
<p>In both cases, the policy was dramatically reduced both in size and in number
of permissions. The decrease in policy size is almost entirely due to removing
unnecessary permissions, many of which were likely rules generated by
audit2allow that were indiscriminately added to the policy. Dead domains were
also an issue for both devices.</p>
<h3 id=granting_the_dac_override_capability>Granting the dac_override capability</h3>
<p>A<code> dac_override</code> denial means that the offending process is
attempting to access a file with the incorrect unix user/group/world permissions.
The proper solution is almost never to grant the <code>dac_override</code> permission.
Instead <a href="https://android-review.googlesource.com/#/c/174530/5/update_engine.te@11">
change the unix permissions on the file or process</a>. A few domains such as
init, vold, and installd genuinely need the ability to override unix file
permissions to access other processes’ files. See
<a href="http://danwalsh.livejournal.com/69478.html">Dan Walsh’s blog</a>
for a more in-depth explanation.</p>
<h2 id=additional_resources>Additional resources</h2>
<p>The <a href="http://seandroid.bitbucket.org/ForMoreInformation.html">SEAndroid
mailing list</a> is an excellent place to ask questions or request a code review.</p>
<p>AOSP provides a concise overview of <a href="index.html">SELinux on Android</a>.</p>
<p>A more in-depth description is available
<a href="http://seandroid.bitbucket.org/">here</a>.</p>