Android HAL in-depth exploration (6): HIDL adds SELinux complete debugging process

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 canbusthe 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 initthe process cannot start vendor.hw_canbusthe service because its executable /system/bin/hw/[email protected]does not have the correct SELinux label, or there are no u:r:init:s0translation 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 initbe 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 canbusadd rules for the service.

The standard Android policy is located in the directory , system/sepolicywhich has the following subdirectories:
In the standard Android SELinux policy structure, the three subdirectories of and system/sepolicyunder the directory each have specific purposes. Here is their basic description and purpose:privatepublicvendor

  1. 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.

  2. private :
    This directory contains publicprivate 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 files compatin the directory that are used to ensure backward compatibility of the policy.

  3. 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_defaultand hal_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 and system/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_serverthe 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 initprocesses 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.
    • init_daemon_domain(hal_canbus_default): This macro defines a initdaemon domain started by a process and has the following properties:

      • Inheriting init_daemonthe rules of the type, this is a general daemon type that contains some basic permissions and constraints.
      • Allows initprocesses to be created, started, stopped, restarted, etc.
      • Allows reading own executable and data files.
      • Allows access to some system properties and logging services.

public directory

  • Add in attributes:

    hal_attribute(canbus);
    

    This line indicates that canbusa 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 attribute canbusis assigned to the HAL interface name hal_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 are hal_canbus_clientand hal_canbus_server. These two types are hal_attribute(canbus)automatically generated by this attribute and represent any canbusclient 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 are hal_canbus_serverand hal_canbus_hwservice. These two types are hal_attribute(canbus)automatically generated by this attribute and represent canbusthe 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 are hal_canbus_client, hal_canbus_hwserviceand hwservice_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::ICanBusis 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.cilprivate/compat/26.0/26.0.ignore.cil

    hal_canbus_hwservice
    

    This line says that we added our HwBinder service type hal_canbus_hwserviceto 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 publicthe 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.privateprebuilts/api/30.0/publicprebuilts/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_defaultand hal_can_bus_default_exec.
  • hal_can_bus_defaultPermissions related to the Hardware Abstraction Layer (HAL) are defined .
  • Allow hal_can_bus_defaultaccess serial_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_contextsthe file.

  • android.hardware.can_bus::ICanBusAdded 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_contextsthe 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.bpthe file.

  • Change the installation location of the HAL service from systempartition to vendorpartition, this is vendor: trueachieved 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 :

These steps ensure that the new HAL service is deployed correctly in vendorthe 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/vendorthe directory, create a new SELinux policy file hal_can_bus_default_vndk.te.

2. Update hwservice_contexts :

  • In device/rockchip/rk356x/sepolicy/vendorthe directory, modify or create hwservice_contextsfiles.

3. Update file context :

  • In device/rockchip/rk356x/sepolicy/vendorthe directory, modify or create file_contextsfiles.

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 +252adding sepolicy to your project.Insert image description here


The difference between Android's SELinux policy structure

In Android's SELinux policy structure, system/sepolicyand device/<manufacturer>/<device>/sepolicyare the locations used to define and customize SELinux policies. But there are some key differences and uses between them:

  1. 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.

  2. 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 will system/sepolicybe merged with the policy in to form a complete SELinux policy.

Merger process :
During the Android build process, the policy files in system/sepolicyand device/<manufacturer>/<device>/sepolicywill be merged together. This is done automatically through Android's build system. If device/<manufacturer>/<device>/sepolicythe policy in system/sepolicyconflicts with the policy in , the build process will fail.

Why can it be added successfully under device?: When
adding device/<manufacturer>/<device>/sepolicya 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/sepolicyProvides default SELinux policies for Android systems, device/<manufacturer>/<device>/sepolicyallowing 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/vendorThe 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 /systemthe partition.

/systemvs /vendoraccess 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 /vendorin means device manufacturers can update hardware support code without having to wait for the entire Android OS to be updated.

/vendorPartitions are designed to be /systemisolated from partitions. This means that /vendorcode in should not depend on /systemlibraries 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 /vendorthe executable in is trying to link against a /systemlibrary in , this is not allowed. To solve this problem, you need to ensure that all /vendorexecutables and libraries required by the service are also located in /vendor.

From a SELinux policy perspective, /systemand /vendorare also isolated. This means that /systemprocesses in cannot by default access /vendorresources in and vice versa.

Test and verify

canbusAfter 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 file u: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 be u: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 canbusadded 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 canbusservice 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!

Guess you like

Origin blog.csdn.net/SHH_1064994894/article/details/132783255