Android strongly encourages OEMs to test their SELinux implementations thoroughly. As manufacturers implement SELinux, they should apply the new policy to a test pool of devices first.
After applying a new policy, make sure SELinux is running in the correct
mode on the device by issuing the command getenforce
.
This prints the global SELinux mode: either Enforcing or Permissive. To
determine the SELinux mode for each domain, you must examine the corresponding
files or run the latest version of sepolicy-analyze
with the
appropriate (-p
) flag, present in
/platform/system/sepolicy/tools/
.
Reading denials
Check for errors, which are routed as event logs to dmesg
and logcat
and are viewable locally on the device. Manufacturers
should examine the SELinux output to dmesg
on these devices and
refine settings prior to public release in permissive mode and eventual switch
to enforcing mode. SELinux log messages contain avc:
and so may
easily be found with grep
. It is possible to capture the ongoing
denial logs by running cat /proc/kmsg
or to capture denial logs
from the previous boot by running
cat /sys/fs/pstore/console-ramoops
.
With this output, manufacturers can readily identify when system users or components are in violation of SELinux policy. Manufacturers can then repair this bad behavior, either by changes to the software, SELinux policy, or both.
Specifically, these log messages indicate what processes would fail under enforcing mode and why. Here is an example:
avc: denied { connectto } for pid=2671 comm="ping" path="/dev/socket/dnsproxyd" scontext=u:r:shell:s0 tcontext=u:r:netd:s0 tclass=unix_stream_socket
Interpret this output like so:
- The
{ connectto }
above represents the action being taken. Together with thetclass
at the end (unix_stream_socket
), it tells you roughly what was being done to what. In this case, something was trying to connect to a unix stream socket. - The
scontext (u:r:shell:s0)
tells you what context initiated the action. In this case this is something running as the shell. - The
tcontext (u:r:netd:s0)
tells you the context of the action’s target. In this case, that’s a unix_stream_socket owned bynetd
. - The
comm="ping"
at the top gives you an additional hint about what was being run at the time the denial was generated. In this case, it’s a pretty good hint.
Another example:
adb shell su root dmesg | grep 'avc: '
Output:
<5> type=1400 audit: avc: denied { read write } for pid=177 comm="rmt_storage" name="mem" dev="tmpfs" ino=6004 scontext=u:r:rmt:s0 tcontext=u:object_r:kmem_device:s0 tclass=chr_file
Here are the key elements from this denial:
- Action - the attempted action is highlighted in brackets,
read write
orsetenforce
. - Actor - The
scontext
(source context) entry represents the actor, in this case thermt_storage
daemon. - Object - The
tcontext
(target context) entry represents the object being acted upon, in this case kmem. - Result - The
tclass
(target class) entry indicates the type of object being acted upon, in this case achr_file
(character device).
Switching to permissive
SELinux enforcement can be disabled via ADB on userdebug or eng builds. To do so,
first switch ADB to root by running adb root
. Then, to disable SELinux
enforcement, run:
adb shell setenforce 0
Or at the kernel command line (during early device bring-up):
androidboot.selinux=permissive
androidboot.selinux=enforcing
Using audit2allow
The selinux/policycoreutils/audit2allow
tool takes
dmesg
denials and converts them into corresponding SELinux policy
statements. As such, it can greatly speed SELinux development.
audit2allow
is shipped as part of the Android source tree and
is compiled automatically when you build Android from source.
To use it, run:
adb pull /sys/fs/selinux/policy
adb logcat -b all -d | audit2allow -p policy
Nevertheless, care must be taken to examine each potential addition for
overreaching permissions. For example, feeding audit2allow
the
rmt_storage
denial shown earlier results in the following
suggested SELinux policy statement:
#============= shell ============== allow shell kernel:security setenforce; #============= rmt ============== allow rmt kmem_device:chr_file { read write };
This would grant rmt
the ability to write kernel memory, a
glaring security hole. Often the audit2allow
statements are only a
starting point. After employing these statements, you may need to change the
source domain and the label of the target, as well as incorporate proper
macros, to arrive at a good policy. Sometimes the denial being examined should
not result in any policy changes at all; rather the offending application
should be changed.