You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
312 lines
12 KiB
312 lines
12 KiB
<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>
|
|
|