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 Supporting documentation for suggested resources.
Here is a brief summary of the steps needed to implement SELinux on your Android device:
init
its own domain.
dmesg
output.
ps -Z | grep init
output to see which services are running in the init domain.
Ideally, OEMs start with the policies in the AOSP and then build upon them for their own customizations.
SELinux for Android is accompanied by everything you need to enable SELinux now. You merely need to integrate the latest Android kernel and then incorporate the files found in the system/sepolicy directory:
https://android.googlesource.com/kernel/common/
https://android.googlesource.com/platform/system/sepolicy/
Those files when compiled comprise the SELinux kernel security policy and cover the upstream Android operating system. You should not need to modify the system/sepolicy files directly. Instead, add your own device-specific policy files within the /device/manufacturer/device-name/sepolicy directory.
Here are the files you must create or edit in order to implement SELinux:
Important: Do not alter the app.te file provided by the Android Open Source Project. Doing so risks breaking all third-party applications.
restorecon
on the file to be
relabeled. On upgrades, changes to file_contexts 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
restorecon_recursive calls to your init.board.rc file after the
partition has been mounted read-write.
Then just update your BoardConfig.mk makefile - located in the directory containing the sepolicy subdirectory - to reference the sepolicy subdirectory and each policy file once created, as shown below. The BOARD_SEPOLICY variables and their meaning is documented in the system/sepolicy/README file.
BOARD_SEPOLICY_DIRS += \ <root>/device/manufacturer/device-name/sepolicy BOARD_SEPOLICY_UNION += \ genfs_contexts \ file_contexts \ sepolicy.te
Note: As of the M release, BOARD_SEPOLICY_UNION is no longer required as all policy files found within any directory included in the BOARD_SEPOLICY_DIRS variable are joined with the base policy automatically.
After rebuilding your device, it 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 Customization or verify your existing setup as covered in Validation.
Once the new policy files and BoardConfig.mk updates are in place, the new policy settings are automatically built into the final kernel policy file.
Here are specific examples of exploits to consider when crafting your own software and associated SELinux policies:
Symlinks - Because symlinks appear as files, they are often read just as that. This can lead to exploits. For instance, some privileged components such as init change the permissions of certain files, sometimes to be excessively open.
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.
System files - Consider the class of system files that should only be modified by the system server. Still, since netd, init, and vold run as root, they can access those system files. So if netd became compromised, it could compromise those files and potentially the system server itself.
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 netd became compromised, it could not switch domains to the system server domain and access those system files although it runs as root.
App data - 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.
setattr - For commands such as chmod and chown, you could identify the set of files where the associated domain can conduct setattr. Anything outside of that could be prohibited from these changes, even by root. So an application might run chmod and chown against those labeled app_data_files but not shell_data_files or system_data_files.
Here is a detailed view of how Android recommends you employ and customize SELinux to protect your devices:
CONFIG_SECURITY_SELINUX=y
BOARD_KERNEL_CMDLINE := androidboot.selinux=permissive
adb shell su -c dmesg | grep denied | audit2allow -p out/target/product/BOARD/root/sepolicy
adb shell su -c dmesg | grep denied | audit2allow
init
, for instance, should have their own. The following commands help reveal those that remain running (but ALL services need such a treatment):adb shell su -c ps -Z | grep init
adb shell su -c dmesg | grep 'avc: '
init
accesses with ones that are in their own policy.
BOARD_CONFIG.mk
to use BOARD_SEPOLICY_*
variables. See
the README in system/sepolicy for details on setting this up.