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 do not
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 via inter-process communication (IPC) to the vendor init
subprocess, which runs the command and sends the result back to init.
Using 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 will 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 are not
part of the stable system-vendor ABI.
- If the SELinux label is new and is not already granted permissions in the
system
vendor_init.te
nor excluded permissions via the neverallow
rules, the new label may be granted permissions in the device-specific
vendor_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.