page.title=Validating SELinux @jd:body
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.
Once applied, make sure SELinux is running in the correct mode on the device by issuing the command:getenforce
This will print the global SELinux mode: either Disabled, Enforcing, or
Permissive. Please note, this command shows only the global SELinux mode. 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/external/sepolicy/tools/.
Then check for errors. Errors 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 /proc/last_kmsg
.
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:
{ connectto }
above represents the action being taken. Together with the
tclass
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.
scontext (u:r:shell:s0)
tells you what context initiated the action. In
this case this is something running as the shell.
tcontext (u:r:netd:s0)
tells you the context of the action’s target. In
this case, that’s a unix_stream_socket owned by netd
.
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.
And here is another example:
$ adb shell su -c dmesg | grep 'avc: ' <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:
read write
or setenforce
.
scontext
(source context) entry represents the actor, in this case the rmt_storage
daemon.
tcontext
(target context) entry represents the object being acted upon, in this case
kmem.
tclass
(target class) entry indicates the type of object being acted upon, in this
case a chr_file
(character device).
Important: Permissive mode is not supported on production devices. CTS tests confirm enforcing mode is enabled.
To turn a device’s SELinux enforcement into globally permissive via ADB, as root issue:
$ adb shell su -c setenforce 0
Or at the kernel command line (during early device bring-up):
androidboot.selinux=permissive androidboot.selinux=disabled androidboot.selinux=enforcing
The selinux/policycoreutils/audit2allow
tool takes dmesg
denials and converts them into corresponding SELinux policy statements. As
such, it can greatly speed SELinux development. To install it, run:
$ sudo apt-get install policycoreutils
To use it on Ubuntu 12.04, run:
$ adb shell su -c dmesg | audit2allow
On Ubuntu 14.04 and newer, audit2allow requires you to specify the Android policy using the -p option, e.g.
$ adb shell su -c dmesg | audit2allow -p out/target/product/<device>/root/sepolicy
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 which changes to the source
domain, the label of the target and the incorporation of proper macros may be
required to arrive at a good policy. Sometimes the denial being examined should
not result in any policy changes at all, but rather the offending application
should be changed.