The init process has nearly unrestricted permissions and uses input scripts from both the system and vendor partitions to initialize the system during the boot process. This access causes a huge hole in the Treble system/vendor split, as vendor scripts may instruct init to access files, properties, etc. that don't form part of the stable system-vendor application binary interface (ABI).
Vendor init is designed to close this hole by using a separate
security-enhanced Linux (SELinux) domain vendor_init
to run
commands found in /vendor
with vendor-specific permissions.
Mechanism
Vendor init forks a subprocess of init early in the boot process with the
SELinux context u:r:vendor_init:s0
. This SELinux context has
considerably fewer permissions than the default init context and its access is
confined to files, properties, etc. that are either vendor-specific or part of
the stable system-vendor ABI.
Init checks each script it loads to see if its path starts with
/vendor
and if so, tags it with an indication that its commands
must be run in the vendor init context. Each init builtin is annotated with a
boolean that specifies whether or not the command must be run in the vendor init
subprocess:
- Most commands that access the file system are annotated to run in the vendor init subprocess and are therefore subjected to the vendor init SEPolicy.
- Most commands that impact internal init state (e.g., starting and stopping services) are run within the normal init process. These commands are made aware that a vendor script is calling them to do their own non-SELinux permissions handling.
The main processing loop of init contains a check that if a command is annotated to run in the vendor subprocess and originates from a vendor script, that command is sent through inter-process communication (IPC) to the vendor init subprocess, which runs the command and sends the result back to init.
Use vendor init
Vendor init is enabled by default and its restrictions apply to all init scripts
present in the /vendor
partition. Vendor init should be transparent
to vendors whose scripts are already not accessing system only files,
properties, etc.
However, if commands in a given vendor script violate the vendor init restrictions, the commands fail. Failing commands have a line in the kernel log (visible with dmesg) from init indicating failure. An SELinux audit accompanies any failing command that failed due to the SELinux policy. Example of a failure including an SELinux audit:
type=1400 audit(1511821362.996:9): avc: denied { search } for pid=540 comm="init" name="nfc" dev="sda45" ino=1310721 scontext=u:r:vendor_init:s0 tcontext=u:object_r:nfc_data_file:s0 tclass=dir permissive=0 init: Command 'write /data/nfc/bad_file_access 1234' action=boot (/vendor/etc/init/hw/init.walleye.rc:422) took 2ms and failed: Unable to write to file '/data/nfc/bad_file_access': open() failed: Permission denied
If a command fails, there are two options:
- If the command is failing due to an intended restriction (such as if the command is accessing a system file or property), the command must be re-implemented in a Treble-friendly way, going through only stable interfaces. Neverallow rules prevent adding permissions to access system files that aren't part of the stable system-vendor ABI.
- If the SELinux label is new and isn't already granted permissions in the
system
vendor_init.te
nor excluded permissions through the neverallow rules, the new label may be granted permissions in the device-specificvendor_init.te
.
For devices launching before Android 9, the neverallows rules may be bypassed by
adding the data_between_core_and_vendor_violators
typeattribute to
the device-specific vendor_init.te
file.
Code locations
The bulk of the logic for the vendor init IPC is in system/core/init/subcontext.cpp.
The table of commands is in the BuiltinFunctionMap
class in system/core/init/builtins.cpp
and includes annotations that indicate if the command must run in the vendor
init subprocess.
The SEPolicy for vendor init is split across the private (system/sepolicy/private/vendor_init.te) and public (system/sepolicy/public/vendor_init.te) directories in system/sepolicy.