| <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> |