Security/Sandbox/SELinux
What is SELinux
Use in B2G
Starting with Android 5.0 (L), SELinux runs in full enforcement mode. Therefore, B2G versions based on Android L are required to have SELinux domains defined for B2G related processes and files (Bug 1136032). This section covers the use of SELinux in B2G.
Policy Files
Generic
Rules that stay consistent across different devices are maintained inside the gonk-misc repository. In particular, the sepolicy/ directory contains the policy files that define the B2G domains and also their rules. During build time, b2g.mk tells the build system to include those files when creating the policy for the system:
BOARD_SEPOLICY_DIRS += \ gonk-misc/sepolicy BOARD_SEPOLICY_UNION += \ b2g.te \ bluetoothd.te \ fakeappops.te \ gonksched.te \ nfcd.te \ plugin-container.te \ rilproxy.te \ file_contexts
The general convention is that one file corresponds to one domain (and rules that belong to that domain) and the file name reflects the domain name. file_contexts is a special file and contains information about which file on the file system has to be labeled with which domain. For example the following line (from file_contexts):
/system/b2g/b2g u:object_r:b2g_exec:s0
labels the executable b2g, inside /system/b2g/, with the domain b2g_exec (defined in b2g.te)
Device Specific
In may be required that the one (or multiple) of the generic domains, can interact with a domain that is defined by the vendor and therefore specific to that device. Maintaining those rules alongside the generic rules would result in failed builds, because a specific domain may not be defined on another device. Because of this, device specific rules are maintained along with other device specific files which reside in the device/ directory in the B2G root folder. In case of the Nexus 5, the device specific rules are maintained inside sepolicy directory of the device-hammerhead repository. This is also the location where the vendor defines its own domains.
Rules that allow the interaction with any of the B2G domains, are defined inside the b2g-vendor.te file. The following shows an excerpt of the file:
allow b2g persist_wifi_file:file { read getattr open };
This rule, allows the b2g domain to read (among other operations) files that are labeled with the persist_wifi_file domain which is only defined on the Nexus 5.
The location of the device specific policies for each device is given by the following table (path relative to B2G root directory):
Device | Path |
---|---|
Nexus 5 | ./device/lge/hammerhead/sepolicy/ |
Flame | ./device/t2m/flame/sepolicy/ |
Rules
audit2allow
At the time of writing, B2G related policy files contain a lot of rules and some of them might not make perfect sense. These rules are generated based off of logged denials during the use of the phone. Whenever a operation is denied, SELinux will log the incident in either dmesg or logcat. A tool called audit2allow parses these log messages and generates rules that allows the denied operation.
The rules that a currently present are all generated with audit2allow, this approach was chosen to simply make Android L based B2G versions 'work'. The defined rules can be used as a basis to further tighten the permissions. For example by locating the correct location inside the code base that triggers the allowed operation and evaluate its usefulness.
Neverallow
Android defines some neverallow rules that forbid certain operations for any domain (with some exceptions). For example:
neverallow { domain -system_server } security_file:dir { rename write add_name remove_name rmdir };
This rule forbids any domain (except for the system_server domain) to write into a directory that is labeled with the domain security_file.
Currently, B2G is not able to comply with those rules and needs to be white-listed in order to guarantee its working. These changes are maintained in the platform_external_sepolicy repository, which also contains the domains and rules defined by Android. For the above mentioned example, the line would be changed to the following:
neverallow { domain -system_server -b2g } security_file:dir { rename write add_name remove_name rmdir };
Troubleshooting
How do I check in what mode SELinux is running?
In order to check in what mode SELinux is currently running, you will have to adb shell onto the device and run getenforce, or run adb shell getenforce. This will return either:
- Permissive - rules are not enforced, but denials are still logged to see what would have been denied
- Enforcing - rules are enforced and a denied operation is indeed denied
Where do I find the logged denials?
Logged denials can either be found by looking at adb shell dmesg or by checking adb logcat, a typcial denial log entry looks like this (from dmesg):
avc: denied { read } for pid=659 comm="b2g.sh" path="/system/bin/sh" dev="mmcblk0p25" ino=212 scontext=u:r:b2g:s0 tcontext=u:object_r:shell_exec:s0 tclass=file
Which is read as:
A process called 'b2g.sh', labeled with u:r:b2g:s0, tried to read the file '/system/bin/sh' which is labeled with u:object_r:shell_exec, and this operation has been denied.
To allow this operation, the following allow statement would have to added to the policy:
allow b2g shell_exec:file read;
How can I check if SELinux is the cause of my problems?
It is possible to temporarily switch to Permissive mode and see if the problem still exists. To switch SELinux mode, run either of the following commands:
adb shell setenforce 0 # switch to Permissive mode adb shell setenforce 1 # switch to Enforcing mode
I am sure SELinux is the problem, but I don't see any log entries?
SELinux provides a rule that suppress log entries, because if every denial of a certain operation would be logged the log file would be filled with a lot of noise. The keyword to look for (inside the policy files) is dontaudit, an example entry is shown below:
dontaudit b2g shell_exec:file read;
If the above line is set, than every denied attempt to read a file labeled with shell_exec by a process labeled with b2g would not be visible in the log files. For testing purpose, you can comment out the dontaudit lines inside the policies and rebuild the policy. You should now see all denied operations.
To find all dontaudit lines, you can simply grep for them in the policy folders. Here is an example grep command (path relative to B2G root directory):
grep -rn 'dontaudit' ./external/sepolicy/
More information
- SELinux tutorial: https://wiki.gentoo.org/wiki/SELinux/Tutorials
- SELinux in Android: http://source.android.com/devices/tech/security/selinux/