In this article, I will introduce how to add SELinux policy (sharing standards and platform methods) to a new HIDL service to ensure that it can run normally in the Android system. I will take
canbus
the service as an example to show the complete process from error reporting to resolution.
Series of articles:
Android HAL in-depth exploration (1): Architecture overview
Android HAL in-depth exploration (2): Traditional HAL and file encryption and decryption simulation
Android HAL in-depth exploration (3): HIDL Passthrough mode and serial port data callback simulation
Android HAL in-depth exploration (4 ): HIDL Binderized mode and CAN data callback simulation
Android HAL in-depth exploration (5): Debugging HAL error reports and solutions
Error analysis
After going through a lot of hardships, I finally solved the HAL code, VNDK and other issues and successfully compiled and burned them! I was full of expectations and thought that the service would be able to start up. After booting up, I found that the can service did not start automatically (the strikeout line is an error situation, and it is there in the correct situation, so I will give you a comparison:)
rk3568_r:/ # ps -A | grep can
system 279 1 10774936 4732 binder_thread_read 0 S [email protected]
rk3568_r:/ # lshal | grep can
FM N [email protected]::ICanBus/default 0/1 279 139
My first reaction was that /system/etc/init/[email protected]
it was not started, so I tried to execute it manually /system/bin/hw/[email protected]
, and logcat reported an error:
09-09 18:43:59.784 0 0 E init : Control message: Could not ctl.start for 'vendor.hw_canbus' from pid: 6533 (start vendor.hw_canbus): File /system/bin/hw/[email protected](labeled "u:object_r:system_file:s0") has incorrect label or no domain transition from u:r:init:s0 to another SELinux domain defined. Have you configured your service correctly? https://source.android.com/security/selinux/device-policy#label_new_services_and_address_denials
09-09 18:44:00.004 1075 1075 D KeyguardClockSwitch: Updating clock: 下午6:44
/system/bin/hw/[email protected]
Contents of the result
This error tells us that init
the process cannot start vendor.hw_canbus
the service because its executable /system/bin/hw/[email protected]
does not have the correct SELinux label, or there are no u:r:init:s0
translation rules from to another SELinux domain. Need to modify the SELinux policy to define a new domain and label for this service and allow it to init
be started from the process? Even if I forcibly turn off SELinux, I can't get around this problem. It seems that this problem must be solved. SELinux takes up at least half of my entire debugging process. I ** you **.
In order to make the next addition smooth, and for everyone to learn from it, I plan to summarize an SOP that I understand to be the easiest way. If the goal is clear, please read on.
Method 1: Modify Android standard SELinux policy
After studying, I learned that in the Android system, the SELinux policy is divided into two parts: platform policy and supplier policy. Platform policies define rules for system services and applications, and vendor policies define rules for hardware abstraction layer (HAL) services and device drivers. The supplier policy needs to be modified to canbus
add rules for the service.
The standard Android policy is located in the directory , system/sepolicy
which has the following subdirectories:
In the standard Android SELinux policy structure, the three subdirectories of and system/sepolicy
under the directory each have specific purposes. Here is their basic description and purpose:private
public
vendor
-
public :
This directory contains the public SELinux policies for the Android platform. These policies are required for all Android devices. It defines policies for the Android framework and core system services. These are part of AOSP and are generally not recommended to be modified by device manufacturers. -
private :
This directory containspublic
private policies that match the public policies in the directory. These policies generally should not be used or modified directly by outside developers or device manufacturers. It also contains files such as filescompat
in the directory that are used to ensure backward compatibility of the policy. -
vendor :
This directory is provided for device manufacturers or SoC vendors to define SELinux policies for their hardware or specific implementation. Device manufacturers can add their own policies here to ensure that their hardware and specific services function properly in SELinux enforcement mode. These policies are device-specific and may vary from device to device.
When building an Android system, the policies in these three directories are merged to produce the final SELinux policy that will be enforced on the device.
According to actual needs, the following modifications need to be made in these directories:
vendor directory
-
Add in
file_contexts
:/(vendor|system)/bin/hw/android\.hardware\.canbus@1\.0-service u:object_r:hal_canbus_default_exec:s0
This line indicates that the executable has
/vendor/bin/hw/[email protected]
either/system/vendor/bin/hw/[email protected]
been given a new SELinux label (depending on where we put it):u:object_r:hal_canbus_default_exec:s0
. This tag consists of three parts: user (u), role (object_r) and type (hal_canbus_default_exec). Users and roles are usually fixed, and types are self-defined. The naming rule of the type is: hal_service name_default_exec. Default indicates that this is a default domain conversion label, and exec indicates that this is an executable file type. -
New
hal_canbus_default.te
:type hal_canbus_default, domain; hal_server_domain(hal_canbus_default, hal_canbus) type hal_canbus_default_exec, exec_type, vendor_file_type, file_type; init_daemon_domain(hal_canbus_default)
This file defines two new types:
hal_canbus_default
andhal_canbus_default_exec
. The former is the domain type of the service process, and the latter is the type of the service executable file. Some macros are also used to define these types of properties and rules. These macros are provided by vendor policies andsystem/sepolicy/public/
their definitions can be found in the directory. The following two macros are used here:-
hal_server_domain(hal_canbus_default, hal_canbus)
: This macro defines a HAL service domain, which has the following attributes:- Inheriting
hal_server
the rules of the type, this is a general HAL service type that contains some basic permissions and constraints. - Allows using HwBinder for IPC communication, including receiving requests from the client, sending callbacks to the client, registering your own service name with the HwBinder service manager, etc.
- Allows access to own executable and data files.
- Allows access to some system properties and logging services.
- Allows
init
processes to be started and stopped.
This macro also requires a parameter, indicating the HAL interface name corresponding to this HAL service domain. In our example, the interface name is
hal_canbus
. This parameter will be used to generate some rules and labels, such as:type hal_canbus, hal_attribute;
: This type represents a HAL attribute, used to identify which HAL interface this HAL service domain belongs to.type hal_canbus_hwservice, hwservice_manager_type;
: This type represents a HwBinder service type and is used to identify the name of this HAL service registered in the HwBinder service manager.add_hwservice(hal_canbus_default, hal_canbus_hwservice)
: This macro allows this HAL service domain to add its own service name to the HwBinder service manager.
- Inheriting
-
init_daemon_domain(hal_canbus_default)
: This macro defines ainit
daemon domain started by a process and has the following properties:- Inheriting
init_daemon
the rules of the type, this is a general daemon type that contains some basic permissions and constraints. - Allows
init
processes to be created, started, stopped, restarted, etc. - Allows reading own executable and data files.
- Allows access to some system properties and logging services.
- Inheriting
-
public directory
-
Add in
attributes
:hal_attribute(canbus);
This line indicates that
canbus
a new attribute is assigned to this HAL interface name:hal_attribute(canbus)
. This attribute is used to identify which HAL version this HAL interface belongs to. In the Android system, there are different versions of HAL interfaces, such as VINTF and HIDL. Different versions of HAL interfaces have different rules and constraints. In order to distinguish them, each HAL interface name needs to be assigned a corresponding attribute. In the example, HIDL is used as the HAL interface version, so this attributecanbus
is assigned to the HAL interface namehal_attribute(canbus)
. -
New
hal_canbus.te
:# HwBinder IPC from client to server, and callbacks binder_call(hal_canbus_client, hal_canbus_server) binder_call(hal_canbus_server, hal_canbus_client) add_hwservice(hal_canbus_server, hal_canbus_hwservice) allow hal_canbus_client hal_canbus_hwservice:hwservice_manager find;
This file defines some rules for HIDL IPC communication. The following macros are used:
-
binder_call(hal_canbus_client, hal_canbus_server)
: This macro allows HwBinder IPC communication between a HAL client domain and a HAL server domain, including sending and receiving requests and callbacks. This macro requires two parameters, which are the types of the client domain and the server domain. In the example these two types arehal_canbus_client
andhal_canbus_server
. These two types arehal_attribute(canbus)
automatically generated by this attribute and represent anycanbus
client or server domain that uses this HAL interface. -
add_hwservice(hal_canbus_server, hal_canbus_hwservice)
: This macro allows a HAL server domain to add its own service name to the HwBinder service manager. This macro requires two parameters, which are the type of server domain and the type of service name. In the example, the two types arehal_canbus_server
andhal_canbus_hwservice
. These two types arehal_attribute(canbus)
automatically generated by this attribute and representcanbus
the server domain and service name using this HAL interface. -
allow hal_canbus_client hal_canbus_hwservice:hwservice_manager find;
: This rule allows a HAL client domain to look up a HAL service name in the HwBinder Service Manager. This rule requires three parameters, which are the type of client domain, the type of service name and the class of HwBinder service manager. In the example, these three parameters arehal_canbus_client
,hal_canbus_hwservice
andhwservice_manager
. This rule is to allow clients to find our service and establish IPC communication.
-
private directory
-
Add in
hwservice_contexts
:android.hardware.canbus::ICanBus u:object_r:hal_canbus_hwservice:s0
This line indicates that our HIDL interface name
android.hardware.canbus::ICanBus
is given a new SELinux label:u:object_r:hal_canbus_hwservice:s0
. This tag consists of three parts: user (u), role (object_r) and type (hal_canbus_hwservice). Users and roles are usually fixed and types are defined by themselves. The naming rule of the type is: hal_service name_hwservice. hwservice indicates that this is a HwBinder service type. -
In all three files
private/compat/28.0/28.0.ignore.cil
, add:private/compat/27.0/27.0.ignore.cil
private/compat/26.0/26.0.ignore.cil
hal_canbus_hwservice
This line says that we added our HwBinder service type
hal_canbus_hwservice
to the compatibility ignore list. This is to avoid errors when doing SELinux policy checks between different API levels. Because our service is a new HIDL interface, it does not need to exist in the old API level.
Sync to prebuilts
In the last step, we need to synchronize the changes in public
the and directory to the and directory. This is to ensure that platform policies can reference the public types and rules we define and pass SELinux policy checks.private
prebuilts/api/30.0/public
prebuilts/api/30.0/private
You can sync using the following command:
cp vendor/sepolicy/public/attributes prebuilts/api/30.0/public/attributes
cp vendor/sepolicy/public/hal_canbus.te prebuilts/api/30.0/public/hal_canbus.te
cp vendor/sepolicy/private/hwservice_contexts prebuilts/api/30.0/private/hwservice_contexts
cp vendor/sepolicy/private/compat/26.0/26.0.ignore.cil prebuilts/api/30.0/private/compat/26.0/26.0.ignore.cil
cp vendor/sepolicy/private/compat/27.0/27.0.ignore.cil prebuilts/api/30.0/private/compat/27.0/27.0.ignore.cil
cp vendor/sepolicy/private/compat/28.0/28.0.ignore.cil prebuilts/api/30.0/private/compat/28.0/28.0.ignore.cil
modified: system/sepolicy/prebuilts/api/30.0/private/compat/26.0/26.0.ignore.cil
modified: system/sepolicy/prebuilts/api/30.0/private/compat/27.0/27.0.ignore.cil
modified: system/sepolicy/prebuilts/api/30.0/private/compat/28.0/28.0.ignore.cil
modified: system/sepolicy/prebuilts/api/30.0/private/compat/29.0/29.0.ignore.cil
modified: system/sepolicy/prebuilts/api/30.0/private/hwservice_contexts
modified: system/sepolicy/prebuilts/api/30.0/public/attributes
modified: system/sepolicy/prebuilts/api/30.0/public/domain.te
modified: system/sepolicy/private/compat/26.0/26.0.ignore.cil
modified: system/sepolicy/private/compat/27.0/27.0.ignore.cil
modified: system/sepolicy/private/compat/28.0/28.0.ignore.cil
modified: system/sepolicy/private/compat/29.0/29.0.ignore.cil
modified: system/sepolicy/private/hwservice_contexts
modified: system/sepolicy/public/attributes
modified: system/sepolicy/public/domain.te
modified: system/sepolicy/vendor/file_contexts
modified: system/sepolicy/public/hal_canbus.te
modified: system/sepolicy/vendor/hal_canbus_default.te
Method 2: Modify the platform to add SELinux policy for the new HAL service
1. Define new SELinux types and permissions :
- Create a new SELinux policy file
device/rockchip/common/sepolicy/vendor/hal_can_bus_default_vndk.te
. - In this file, new SELinux types
hal_can_bus_default
andhal_can_bus_default_exec
. hal_can_bus_default
Permissions related to the Hardware Abstraction Layer (HAL) are defined .- Allow
hal_can_bus_default
accessserial_device
.type hal_can_bus_default, domain; hal_server_domain(hal_can_bus_default, hal_can_bus) type hal_can_bus_default_exec, exec_type, vendor_file_type, file_type; init_daemon_domain(hal_can_bus_default) allow hal_can_bus_default serial_device:chr_file rw_file_perms;
2. Update hwservice_contexts :
-
Modify
device/rockchip/common/sepolicy/vendor/hwservice_contexts
the file. -
android.hardware.can_bus::ICanBus
Added a SELinux context for the new HAL service .+android.hardware.can_bus::ICanBus u:object_r:hal_can_bus_hwservice:s0
3. Update file context :
-
Modify
device/rockchip/common/sepolicy/vendor/file_contexts
the file. -
[email protected]
A SELinux context is defined for the new HAL service executable .+/(vendor|system/vendor)/bin/hw/android\.hardware\.can_bus@1\.0-service u:object_r:hal_can_bus_default_exec:s0
4. Modify the build configuration of HAL :
-
Modify
hardware/interfaces/can_bus/1.0/service/Android.bp
the file. -
Change the installation location of the HAL service from
system
partition tovendor
partition, this isvendor: true
achieved by adding.cc_binary { name: "[email protected]", relative_install_path: "hw", init_rc: ["[email protected]"], srcs: [ "CanBusService.cpp", ], shared_libs: [ "liblog", "libutils", "libhidlbase", "libhwbinder", "[email protected]", ], + vendor: true, }
5. Update the init.rc file of the service :
-
Modify
[email protected]
the file. -
Change the path of the service
/vendor/bin/hw/[email protected]
to make sure itvendor
starts correctly in the partition.+service vendor.hw_canbus /vendor/bin/hw/[email protected]
These steps ensure that the new HAL service is deployed correctly in vendor
the partition and has the appropriate SELinux context and permissions. This is the typical way to customize Android SELinux policies for a specific device or hardware platform.
Method 3: Modify the platform to add SELinux policy for the new HAL service (project version)
Referring to the basis of method 2 , we should add the corresponding content in the device/rockchip/rk356x/sepolicy/vendor/hwservice_contexts file instead of in the common directory. This is done to avoid conflicts with policy files for other devices or platforms and to make it easier to identify and maintain your own policy files. (Assume rk356x is the project name)
1. Define new SELinux types and permissions :
- Under
device/rockchip/rk356x/sepolicy/vendor
the directory, create a new SELinux policy filehal_can_bus_default_vndk.te
.
2. Update hwservice_contexts :
- In
device/rockchip/rk356x/sepolicy/vendor
the directory, modify or createhwservice_contexts
files.
3. Update file context :
- In
device/rockchip/rk356x/sepolicy/vendor
the directory, modify or createfile_contexts
files.
4. Modify BoardConfig.mk :
-
In
BoardConfig.mk
, add the following variables to specify the location and contents of the SELinux policy file.BOARD_SEPOLICY_VENDOR_DIRS += \ <root>/device/rockchip/rk356x/sepolicy/vendor BOARD_SEPOLICY_VENDOR_UNION += \ file_contexts \ hal_can_bus_default_vndk.te \ hwservice_contexts
You can also refer to device/rockchip$ vi common/BoardConfig.mk +252
adding sepolicy to your project.
The difference between Android's SELinux policy structure
In Android's SELinux policy structure, system/sepolicy
and device/<manufacturer>/<device>/sepolicy
are the locations used to define and customize SELinux policies. But there are some key differences and uses between them:
-
system/sepolicy :
This is the location of the default SELinux policy provided by AOSP. It defines the basic security policy of the Android system. It is usually not recommended to modify these files directly because they are part of AOSP. In order to avoid coupling and debugging difficulties, it is recommended to modify the platform. -
device///sepolicy :
This is where SELinux policies are customized for a specific device or hardware manufacturer. Usually to support hardware or functionality of a specific device. At compile time, it willsystem/sepolicy
be merged with the policy in to form a complete SELinux policy.
Merger process :
During the Android build process, the policy files in system/sepolicy
and device/<manufacturer>/<device>/sepolicy
will be merged together. This is done automatically through Android's build system. If device/<manufacturer>/<device>/sepolicy
the policy in system/sepolicy
conflicts with the policy in , the build process will fail.
Why can it be added successfully under device?: When
adding device/<manufacturer>/<device>/sepolicy
a policy under device, you are actually adding or overriding the default policy for a specific device. I checked the information and found out in practice that it is possible. In fact, this is the recommended method to customize the SELinux policy for a specific device instead of modifying it directly system/sepolicy
.
system/sepolicy
Provides default SELinux policies for Android systems, device/<manufacturer>/<device>/sepolicy
allowing hardware manufacturers and device maintainers to customize these policies for specific devices. During the build process, the policies for these two locations are merged together.
The difference between Android system and vendor partitions and their importance
/system
/vendor
The difference between vs
/system
: This partition contains the main parts of the Android operating system, including system applications, frameworks, libraries and other core code. For security and stability, this partition is read-only during normal operation./vendor
: This partition contains the device manufacturer's hardware-related code and binaries. This allows manufacturers to update their hardware support code independently of the main Android operating system, thus speeding up device updates.
If not set explicitly vendor: true
, the build system will place the module in /system
the partition.
/system
vs /vendor
access isolation
In Android 8.0 and above, Android's directory structure and access control have undergone significant changes to support Project Treble. Putting hardware-related code and services /vendor
in means device manufacturers can update hardware support code without having to wait for the entire Android OS to be updated.
/vendor
Partitions are designed to be /system
isolated from partitions. This means that /vendor
code in should not depend on /system
libraries in and vice versa.
# 这个错误是我手动将system移动到vendor 直接移动是不行的,要改Android.bp + vendor: true,
vendor/bin/hw/[email protected]
CANNOT LINK EXECUTABLE "vendor/bin/hw/[email protected]": library "libhwbinder.so" not found: needed by main executable
If the error encountered is because /vendor
the executable in is trying to link against a /system
library in , this is not allowed. To solve this problem, you need to ensure that all /vendor
executables and libraries required by the service are also located in /vendor
.
From a SELinux policy perspective, /system
and /vendor
are also isolated. This means that /system
processes in cannot by default access /vendor
resources in and vice versa.
Test and verify
canbus
After the above modifications, the process of adding SELinux policy to the service is completed . To test and verify that the modifications are correct, you can rebuild the system and run the following commands on the device:
ls -Z /vendor/bin/hw/[email protected]
: This command can view the SELinux label of our service executable fileu:object_r:hal_can_bus_default_exec:s0
.
rk3568_r:/vendor # ls -Z /vendor/bin/hw/[email protected]
u:object_r:hal_can_bus_default_exec:s0 /vendor/bin/hw/[email protected]
ps -AT | grep can_bus
: This command can view the SELinux label of the service process, which should beu:r:hal_can_bus_default:s0
.
rk3568_r:/vendor # ps -AZ | grep can_bus
u:r:hal_can_bus_default:s0 system 279 1 10774936 4732 binder_thread_read 0 S [email protected]
-
dmesg | grep avc
: This command can check if there are any SELinux denial logs. There should be no service-related denials. -
lshal debug -E [email protected]::ICanBus/default
: This command can view the detailed information of the service, including its HwBinder handle, reference count, debugging information, etc.
rk3568_r:/vendor # lshal debug -E [email protected]::ICanBus/default
[email protected]::ICanBus/default does not exist, or no permission to connect.
128|rk3568_r:/vendor # lshal | grep can_bus
FM N [email protected]::ICanBus/default 0/1 279 139
If the above commands run normally without any errors or exceptions, it can be considered that the SELinux policy has been successfully canbus
added to the service.
Summarize
It took a lot of time to learn about this permission and verification. During this period, method 1 took the most time. I tried several times to write notes and then checked out. Method 1. I am still a little confused now that the verification is OK. But I still checked out the final method 3.
In this article, I introduce how to add SELinux policy (shared standards and platform methods) to a new HIDL service to ensure that it can run properly in the Android system. I took canbus
service as an example to show the complete process from error reporting to resolution. I hope this article can be helpful to you. If you have any questions or suggestions, please leave them in the comment area. Thanks!