blob: 79846c2f7b6d4ad7db636060346016547ae9b8f8 [file] [log] [blame]
<html devsite>
<head>
<title>Implementing SELinux</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>SELinux is set up to default-deny, which means that every single access for
which it has a hook in the kernel must be explicitly allowed by policy. This
means a policy file is comprised of a large amount of information regarding
rules, types, classes, permissions, and more. A full consideration of SELinux
is out of the scope of this document, but an understanding of how to write
policy rules is now essential when bringing up new Android devices. There is a
great deal of information available regarding SELinux already. See <a
href="/security/selinux#supporting_documentation">Supporting
documentation</a> for suggested resources.</p>
<h2 id="key_files">Key files</h2>
<p>To enable SELinux, integrate the
<a href="https://android.googlesource.com/kernel/common/" class="external">latest
Android kernel</a> and then incorporate the files found in the
<a href="https://android.googlesource.com/platform/system/sepolicy/" class="external">system/sepolicy</a>
directory. When compiled, those files comprise the SELinux kernel security
policy and cover the upstream Android operating system.</p>
<p>In general, you should not modify the <code>system/sepolicy</code> files
directly. Instead, add or edit your own device-specific policy files in the
<code>/device/<var>manufacturer</var>/<var>device-name</var>/sepolicy</code>
directory. In Android 8.0 and higher, the changes you make to these files should
only affect policy in your vendor directory. For more details on separation of
public sepolicy in Android 8.0 and higher, see
<a href="/security/selinux/customize#android-o">Customizing SEPolicy in Android
8.0+</a>. Regardless of Android version, you're still modifying these files:</p>
<h3 id="policy-files">Policy files</h3>
<p>Files that end with <code>*.te</code> are SELinux policy source files, which
define domains and their labels. You may need to create new policy files in
<code>/device/<var>manufacturer</var>/<var>device-name</var>/sepolicy</code>,
but you should try to update existing files where possible.</p>
<h3 id="context-files">Context files</h3>
<p>Context files are where you specify labels for your objects.</p>
<ul>
<li><code>file_contexts</code> assigns labels to files and is used by various
userspace components. As you create new policies, create or update this file
to assign new labels to files. To apply new <code>file_contexts</code>,
rebuild the filesystem image or run <code>restorecon</code> on the file to
be relabeled. On upgrades, changes to <code>file_contexts</code> are
automatically applied to the system and userdata partitions as part of the
upgrade. Changes can also be automatically applied on upgrade to other
partitions by adding <code>restorecon_recursive</code> calls to your
init.<var>board</var>.rc file after the partition has been mounted
read-write.</li>
<li><code>genfs_contexts</code> assigns labels to filesystems, such as
<code>proc</code> or <code>vfat</code> that do not support extended
attributes. This configuration is loaded as part of the kernel policy but
changes may not take effect for in-core inodes, requiring a reboot or
unmounting and re-mounting the filesystem to fully apply the change.
Specific labels may also be assigned to specific mounts, such as
<code>vfat</code> using the <code>context=mount</code> option.</li>
<li><code>property_contexts</code> assigns labels to Android system properties to
control what processes can set them. This configuration is read by the
<code>init</code> process during startup.</li>
<li><code>service_contexts</code> assigns labels to Android binder services to
control what processes can add (register) and find (lookup) a binder
reference for the service. This configuration is read by the
<code>servicemanager</code> process during startup.</li>
<li><code>seapp_contexts</code> assigns labels to app processes and
<code>/data/data</code> directories. This configuration is read by the
<code>zygote</code> process on each app launch and by <code>installd</code>
during startup.</li>
<li><code>mac_permissions.xml</code> assigns a <code>seinfo</code> tag to apps
based on their signature and optionally their package name. The
<code>seinfo</code> tag can then be used as a key in the
<code>seapp_contexts</code> file to assign a specific label to all apps with
that <code>seinfo</code> tag. This configuration is read by
<code>system_server</code> during startup.</li>
</ul>
<h3 id="boardconfig">BoardConfig.mk makefile</h3>
<p>After editing or adding policy and context files, update your
<code>/device/<var>manufacturer</var>/<var>device-name</var>/BoardConfig.mk</code>
makefile to reference the <code>sepolicy</code> subdirectory and each new policy file.
For more information about the <code>BOARD_SEPOLICY</code> variables, see
<a href="https://android.googlesource.com/platform/system/sepolicy/+/master/README" class="external">
<code>system/sepolicy/README</code> file</a>.</p>
<pre class="devsite-click-to-copy">
BOARD_SEPOLICY_DIRS += \
&lt;root&gt;/device/<var>manufacturer</var>/<var>device-name</var>/sepolicy
BOARD_SEPOLICY_UNION += \
genfs_contexts \
file_contexts \
sepolicy.te
</pre>
<p>After rebuilding, your device is enabled with SELinux. You can now either
customize your SELinux policies to accommodate your own additions to the
Android operating system as described in
<a href="/security/selinux/customize.html">Customization</a> or verify your
existing setup as covered in
<a href="/security/selinux/validate.html">Validation</a>.</p>
<p>When the new policy files and BoardConfig.mk updates are in place, the new
policy settings are automatically built into the final kernel policy file.
For more information about how sepolicy is built on the device, see
<a href="security/selinux/building">Building sepolicy</a>.</p>
<h2 id="steps">Implementation</h2>
<p>To get started with SELinux:</p>
<ol>
<li>Enable SELinux in the kernel:
<code>CONFIG_SECURITY_SELINUX=y</code></li>
<li>Change the kernel_cmdline parameter so that:
<pre class="devsite-click-to-copy">
BOARD_KERNEL_CMDLINE := androidboot.selinux=permissive</pre>
This is only for initial development of policy for the device. After you
have an initial bootstrap policy, remove this parameter so your
device is enforcing or it will fail CTS.</li>
<li>Boot up the system in permissive and see what denials are encountered on boot:<br/>
On Ubuntu 14.04 or newer:
<pre class="devsite-terminal devsite-click-to-copy">
adb shell su -c dmesg | grep denied | audit2allow -p out/target/product/<var>BOARD</var>/root/sepolicy
</pre>
On Ubuntu 12.04:
<pre class="devsite-terminal devsite-click-to-copy">
adb pull /sys/fs/selinux/policy
adb logcat -b all | audit2allow -p policy
</pre></li>
<li>Evaluate the output for warnings that resemble <code>init: Warning!
Service name needs a SELinux domain defined; please fix!</code> See
<a href="/security/selinux/validate">Validation</a> for instructions
and tools.</li>
<li>Identify devices, and other new files that need labeling.</li>
<li>Use existing or new labels for your objects. Look at the
<code>*_contexts</code> files to see how things were previously labeled
and use knowledge of the label meanings to assign a new one. Ideally,
this will be an existing label which will fit into policy, but sometimes
a new label will be needed, and rules for access to that label will be
needed. Add your labels to the appropriate context files.</li>
<li>Identify domains/processes that should have their own security domains.
You will likely need to write a completely new policy for each. All
services spawned from <code>init</code>, for instance, should have their
own. The following commands help reveal those that remain running (but ALL
services need such a treatment):<br/>
<pre class="devsite-terminal devsite-click-to-copy">
adb shell su -c ps -Z | grep init
</pre>
<pre class="devsite-terminal devsite-click-to-copy">
adb shell su -c dmesg | grep 'avc: '
</pre></li>
<li>Review <code>init.<var>device</var>.rc</code> to identify any domains that
don't have a domain type. Give them a domain <em>early</em> in your
development process to avoid adding rules to <code>init</code> or
otherwise confusing <code>init</code> accesses with ones that are in their
own policy.</li>
<li>Set up <code>BOARD_CONFIG.mk</code> to use <code>BOARD_SEPOLICY_*</code>
variables. See the
<a href="https://android.googlesource.com/platform/system/sepolicy/+/master/README" class="external">README</a>
in <code>system/sepolicy</code> for details on setting this up.</li>
<li>Examine the init.<var>device</var>.rc and fstab.<var>device</var> file and
make sure every use of <code>mount</code> corresponds to a properly
labeled filesystem or that a <code>context= mount</code> option is
specified.</li>
<li>Go through each denial and create SELinux policy to properly handle each. See
the examples in <a href="/security/selinux/customize">Customization</a>.
</ol>
<p>You should start with the policies in the AOSP and then build upon them for
your own customizations. For more information about policy strategy and a
closer look at some of these steps, see
<a href="/security/selinux/device-policy">Writing SELinux Policy</a>.</p>
<h2 id="use_cases">Use cases</h2>
<p>Here are specific examples of exploits to consider when crafting your own
software and associated SELinux policies:</p>
<p><strong>Symlinks</strong> - Because symlinks appear as files, they are often
read as files, which can lead to exploits. For instance, some privileged
components, such as <code>init</code>, change the permissions of certain files,
sometimes to be excessively open.</p>
<p>Attackers might then replace those files with symlinks to code they control,
allowing the attacker to overwrite arbitrary files. But if you know your
application will never traverse a symlink, you can prohibit it from doing so
with SELinux.</p>
<p><strong>System files</strong> - Consider the class of system files that
should be modified only by the system server. Still, since <code>netd</code>,
<code>init</code>, and <code>vold</code> run as root, they can access
those system files. So if <code>netd</code> became compromised, it could
compromise those files and potentially the system server itself.</p>
<p>With SELinux, you can identify those files as system server data files.
Therefore, the only domain that has read/write access to them is system server.
Even if <code>netd</code> became compromised, it could not switch domains to the
system server domain and access those system files although it runs as root.</p>
<p><strong>App data</strong> - Another example is the class of functions that
must run as root but should not get to access app data. This is incredibly
useful as wide-ranging assertions can be made, such as certain domains unrelated
to application data being prohibited from accessing the internet.</p>
<p><strong>setattr</strong> - For commands such as <code>chmod</code> and
<code>chown</code>, you could identify the set of files where the associated
domain can conduct <code>setattr</code>. Anything outside of that could be
prohibited from these changes, even by root. So an application might run
<code>chmod</code> and <code>chown</code> against those labeled
<code>app_data_files</code> but not <code>shell_data_files</code>
or <code>system_data_files</code>.</p>
</body>
</html>