在Android 11 init进程对Selinux的处理一文中,我们知道,在init进程对Selinux的处理过程中,会将precompiled_sepolicy或者动态编译相关目录下的cil文件得到的compiled_sepolicy写入给内核。那么precompiled_sepolicy文件和cil文件是从哪里来的呢?
Selinux的编译逻辑基本都是在system\sepolicy\Android.mk文件中
首先关注Android.mk中的几个宏
PLAT_PUBLIC_POLICY := system/sepolicy/public
PLAT_PRIVATE_POLICY := system/sepolicy/private
PLAT_VENDOR_POLICY := system/sepolicy/vendor
SYSTEM_EXT_PUBLIC_POLICY := $(BOARD_PLAT_PUBLIC_SEPOLICY_DIR)
SYSTEM_EXT_PRIVATE_POLICY := $(BOARD_PLAT_PRIVATE_SEPOLICY_DIR)
PRODUCT_PUBLIC_POLICY := $(PRODUCT_PUBLIC_SEPOLICY_DIRS)
PRODUCT_PRIVATE_POLICY := $(PRODUCT_PRIVATE_SEPOLICY_DIRS)
BOARD_SEPOLICY_DIRS
其中BOARD_SEPOLICY_DIRS 可以由厂商自定义路径,这样厂商自己的文件也会加到Selinux的编译系统中。比如
BOARD_SEPOLICY_DIRS ?= \
device/rockchip/common/sepolicy/vendor
precompiled_sepolicy的生成过程
#################################
include $(CLEAR_VARS)
LOCAL_MODULE := precompiled_sepolicy
LOCAL_MODULE_CLASS := ETC
LOCAL_MODULE_TAGS := optional
LOCAL_PROPRIETARY_MODULE := true
ifeq ($(BOARD_USES_ODMIMAGE),true)
LOCAL_MODULE_PATH := $(TARGET_OUT_ODM)/etc/selinux
else
LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR)/etc/selinux
endif
如果有odm分区,目标文件precompiled_sepolicy就放在odm/etc/selinux目录下,否则就放在vendor/etc/selinux目录。
$(LOCAL_BUILT_MODULE): PRIVATE_CIL_FILES := $(all_cil_files)
$(LOCAL_BUILT_MODULE): PRIVATE_NEVERALLOW_ARG := $(NEVERALLOW_ARG)
$(LOCAL_BUILT_MODULE): $(HOST_OUT_EXECUTABLES)/secilc $(all_cil_files) $(built_sepolicy_neverallows)
$(hide) $(HOST_OUT_EXECUTABLES)/secilc -m -M true -G -c $(POLICYVERS) $(PRIVATE_NEVERALLOW_ARG) \
$(PRIVATE_CIL_FILES) -o $@ -f /dev/null
通过secilc,将cil文件编译成目标文件precompiled_sepolicy,其中cil文件包含
all_cil_files := \
$(built_plat_cil) \
$(built_plat_mapping_cil) \
$(built_pub_vers_cil) \
$(built_vendor_cil)
ifdef HAS_SYSTEM_EXT_SEPOLICY
all_cil_files += $(built_system_ext_cil)
endif
ifdef HAS_SYSTEM_EXT_PUBLIC_SEPOLICY
all_cil_files += $(built_system_ext_mapping_cil)
endif
ifdef HAS_PRODUCT_SEPOLICY
all_cil_files += $(built_product_cil)
endif
ifdef HAS_PRODUCT_PUBLIC_SEPOLICY
all_cil_files += $(built_product_mapping_cil)
endif
ifdef BOARD_ODM_SEPOLICY_DIRS
all_cil_files += $(built_odm_cil)
endif
再来看一下cil文件的生成过程,以built_plat_cil 为例,其它的都类似
built_plat_cil
built_plat_cil是在生成plat_sepolicy.cil的时候赋值的
include $(CLEAR_VARS)
LOCAL_MODULE := plat_sepolicy.cil
//省略
built_plat_cil := $(LOCAL_BUILT_MODULE)
plat_sepolicy.cil 会放在system/etc/selinux目录下
include $(CLEAR_VARS)
LOCAL_MODULE := plat_sepolicy.cil
LOCAL_MODULE_CLASS := ETC
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_PATH := $(TARGET_OUT)/etc/selinux
收集 PLAT_PRIVATE_POLICY和 PLAT_PUBLIC_POLICY 目录下的 文件,通过transform-policy-to-conf 进行宏展开,得到plat_policy.conf文件。其中PLAT_PRIVATE_POLICY和PLAT_PUBLIC_POLICY 对应的目录,参考前面提到的Android.mk中的宏
policy_files := $(call build_policy, $(sepolicy_build_files), \
$(PLAT_PUBLIC_POLICY) $(PLAT_PRIVATE_POLICY))
plat_policy.conf := $(intermediates)/plat_policy.conf
$(plat_policy.conf): PRIVATE_MLS_SENS := $(MLS_SENS)
$(plat_policy.conf): PRIVATE_MLS_CATS := $(MLS_CATS)
$(plat_policy.conf): PRIVATE_TARGET_BUILD_VARIANT := $(TARGET_BUILD_VARIANT)
$(plat_policy.conf): PRIVATE_TGT_ARCH := $(my_target_arch)
$(plat_policy.conf): PRIVATE_TGT_WITH_ASAN := $(with_asan)
$(plat_policy.conf): PRIVATE_TGT_WITH_NATIVE_COVERAGE := $(with_native_coverage)
$(plat_policy.conf): PRIVATE_ADDITIONAL_M4DEFS := $(LOCAL_ADDITIONAL_M4DEFS)
$(plat_policy.conf): PRIVATE_SEPOLICY_SPLIT := $(PRODUCT_SEPOLICY_SPLIT)
$(plat_policy.conf): PRIVATE_COMPATIBLE_PROPERTY := $(PRODUCT_COMPATIBLE_PROPERTY)
$(plat_policy.conf): PRIVATE_TREBLE_SYSPROP_NEVERALLOW := $(treble_sysprop_neverallow)
$(plat_policy.conf): PRIVATE_POLICY_FILES := $(policy_files)
$(plat_policy.conf): $(policy_files) $(M4)
$(transform-policy-to-conf)
$(hide) sed '/^\s*dontaudit.*;/d' $@ | sed '/^\s*dontaudit/,/;/d' > $@.dontaudit
sepolicy_build_files 包含的文件有:
sepolicy_build_files := security_classes \
initial_sids \
access_vectors \
global_macros \
neverallow_macros \
mls_macros \
mls_decl \
mls \
policy_capabilities \
te_macros \
attributes \
ioctl_defines \
ioctl_macros \
*.te \
roles_decl \
roles \
users \
initial_sid_contexts \
fs_use \
genfs_contexts \
port_contexts
收集到的文件,宏展开得到plat_policy.conf后,通过checkpolicy生成plat_sepolicy.cil目标文件
$(LOCAL_BUILT_MODULE): PRIVATE_ADDITIONAL_CIL_FILES := \
$(call build_policy, $(sepolicy_build_cil_workaround_files), $(PLAT_PRIVATE_POLICY))
$(LOCAL_BUILT_MODULE): PRIVATE_NEVERALLOW_ARG := $(NEVERALLOW_ARG)
$(LOCAL_BUILT_MODULE): $(plat_policy.conf) $(HOST_OUT_EXECUTABLES)/checkpolicy \
$(HOST_OUT_EXECUTABLES)/secilc \
$(call build_policy, $(sepolicy_build_cil_workaround_files), $(PLAT_PRIVATE_POLICY)) \
$(built_sepolicy_neverallows)
@mkdir -p $(dir $@)
$(hide) $(CHECKPOLICY_ASAN_OPTIONS) $(HOST_OUT_EXECUTABLES)/checkpolicy -M -C -c \
$(POLICYVERS) -o $@.tmp $<
$(hide) cat $(PRIVATE_ADDITIONAL_CIL_FILES) >> $@.tmp
$(hide) $(HOST_OUT_EXECUTABLES)/secilc -m -M true -G -c $(POLICYVERS) $(PRIVATE_NEVERALLOW_ARG) $@.tmp -o /dev/null -f /dev/null
$(hide) mv $@.tmp $@
总结编译的整体逻辑
1,查找相关目录下的te文件,进行宏展开,转化成policy.conf文件。
2,将 policy.conf 文件,通过checkpolicy,编译成中间文件*.cil
3,通过secilc工具,编译成二进制文件precompiled_sepolicy
最终根目录系统结构为
console:/ # ls -al system/etc/selinux/
total 1764
drwxr-xr-x 3 root root 4096 2024-01-17 18:00 .
drwxr-xr-x 14 root root 4096 2024-01-24 16:47 ..
drwxr-xr-x 2 root root 4096 2024-01-17 17:59 mapping
-rw-r--r-- 1 root root 41949 2024-01-17 17:59 plat_file_contexts
-rw-r--r-- 1 root root 8752 2024-01-17 17:59 plat_hwservice_contexts
-rw-r--r-- 1 root root 7371 2024-01-17 17:59 plat_mac_permissions.xml
-rw-r--r-- 1 root root 47325 2024-01-17 17:59 plat_property_contexts
-rw-r--r-- 1 root root 2898 2024-01-17 18:00 plat_seapp_contexts
-rw-r--r-- 1 root root 1646622 2024-01-17 17:59 plat_sepolicy.cil
-rw-r--r-- 1 root root 65 2024-01-17 17:59 plat_sepolicy_and_mapping.sha256
-rw-r--r-- 1 root root 18876 2024-01-17 17:59 plat_service_contexts
console:/ # ls -al vendor/etc/selinux/
total 1184
drwxr-xr-x 2 root shell 4096 2024-01-17 18:00 .
drwxr-xr-x 13 root shell 4096 2024-01-24 16:46 ..
-rw-r--r-- 1 root root 926046 2024-01-17 18:00 plat_pub_versioned.cil
-rw-r--r-- 1 root root 5 2024-01-17 17:59 plat_sepolicy_vers.txt
-rw-r--r-- 1 root root 1511 2024-01-17 17:59 selinux_denial_metadata
-rw-r--r-- 1 root root 21807 2024-01-17 17:59 vendor_file_contexts
-rw-r--r-- 1 root root 280 2024-01-17 17:59 vendor_hwservice_contexts
-rw-r--r-- 1 root root 6751 2024-01-17 17:59 vendor_mac_permissions.xml
-rw-r--r-- 1 root root 3900 2024-01-17 17:59 vendor_property_contexts
-rw-r--r-- 1 root root 0 2024-01-17 18:00 vendor_seapp_contexts
-rw-r--r-- 1 root root 216664 2024-01-17 18:00 vendor_sepolicy.cil
-rw-r--r-- 1 root root 214 2024-01-17 17:59 vendor_service_contexts
-rw-r--r-- 1 root root 130 2024-01-17 18:00 vndservice_contexts
console:/ # ls -al odm/etc/selinux/
total 556
drwxr-xr-x 2 root root 4096 2024-01-17 18:00 .
drwxr-xr-x 3 root root 4096 2024-01-17 18:00 ..
-rw-r--r-- 1 root root 545403 2024-01-17 18:00 precompiled_sepolicy
-rw-r--r-- 1 root root 65 2024-01-17 18:00 precompiled_sepolicy.plat_sepolicy_and_mapping.sha256
-rw-r--r-- 1 root root 65 2024-01-17 18:00 precompiled_sepolicy.product_sepolicy_and_mapping.sha256
-rw-r--r-- 1 root root 65 2024-01-17 18:00 precompiled_sepolicy.system_ext_sepolicy_and_mapping.sha256
上面只是简要的分析了一下编译过程,具体的还需要分析Android.mk文件。
参考Android.mk文件,我们如果更改了Selinux某些内容,可以执行make selinux_policy或者mmma system/sepolicy 进行模块编译就行了,不用整编系统,然后替换system/vendor 下相关的文件即可。