312 lines
12 KiB
HTML
312 lines
12 KiB
HTML
<html devsite>
|
||
<head>
|
||
<title>Writing SELinux Policy</title>
|
||
<meta name="project_path" value="/_project.yaml" />
|
||
<meta name="book_path" value="/_book.yaml" />
|
||
</head>
|
||
<body>
|
||
<!--
|
||
Copyright 2017 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.
|
||
-->
|
||
|
||
|
||
|
||
|
||
|
||
<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–95% of the final on-device policy with device-specific
|
||
customizations making up the remaining 5–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 device’s BoardConfig.mk file:
|
||
<code>platform/device/<vendor>/<target>/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>
|
||
|
||
<pre class="devsite-terminal devsite-click-to-copy">
|
||
adb getenforce
|
||
</pre>
|
||
|
||
|
||
<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>
|
||
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.<target>.rc</code> file as:</p>
|
||
|
||
<pre class="devsite-click-to-copy">
|
||
service foo /system/bin/foo
|
||
class core
|
||
</pre>
|
||
|
||
<ol>
|
||
<li>Create a new domain "foo"<br />
|
||
|
||
<p>Create the file <code>device/<oem>/<target>/sepolicy/foo.te</code>
|
||
with the following contents:</p>
|
||
|
||
<pre class="devsite-click-to-copy">
|
||
# 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/<oem>/<target>/sepolicy/
|
||
file_contexts</code>:</p>
|
||
|
||
<pre class="devsite-click-to-copy">
|
||
/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>
|
||
|
||
<pre>allow { domain -untrusted_app } scary_debug_device:chr_file rw_file_perms</pre>
|
||
|
||
<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–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>
|
||
|
||
</body>
|
||
</html>
|