說明
系統:Android10.0
裝置: FireFly RK3399 (ROC-RK3399-PC-PLUS)
前言
本章節重點介紹在Android源碼中, 涉及selinux政策檔案所在目錄和檔案,以及編譯規則
一, selinux政策所在目錄
system/sepolicy/ | Android核心公共的政策檔案,上下文檔案 |
external/selinux | 外部 SELinux 項目,用于建構主機環境中編譯 SELinux 政策和标簽所需的各種工具,如提供libselinux庫函數,checkpolicy編譯器(policy.conf編譯成cil檔案),secilc編譯器(cil檔案編譯成二進制) |
BOARD_SEPOLICY_DIRS | 闆級/供應商定制或擴充的政策檔案 |
system/sepolicy/:Android核心公共的政策檔案,上下文檔案
tree -L 1 system/sepolicy/
system/sepolicy/
├── Android.bp
├── Android.mk:大部分的編譯目标的規則檔案,會include目前目錄各個mk檔案,如file_contexts.mk等
├── apex
├── build : 提供編譯腳本, 腳本包含了各種編譯指令,如build_cil用于編譯cil檔案
├── CleanSpec.mk
├── definitions.mk :隻定義了transform-policy-to-conf一個函數,将政策檔案轉成conf檔案,生成xx_policy.conf,
本質上是調用m4指令對檔案中的宏進行處理。
├── file_contexts.mk:編譯目标檔案plat_property_context
├── hwservice_contexts.mk
├── mac_permissions.mk
├── policy_version.mk : 指定目前系統API, 如30
├── prebuilts: 提供舊版本的私有和共有政策, 保證系統向下相容,
diff -Nur system/sepolicy/prebuilts/api/29.0/private/ system/sepolicy/private/ 是一樣的。
├── private : 平台私有政策,非平台政策是不能引用和擴充(也可以了解為供應商忽略/不要動)。
├── property_contexts.mk : 編譯目标檔案plat_property_context以及vendor_property_contexts的規則
在out/target/product/rk3399_roc_pc_plus/obj/ETC/plat_property_contexts_intermediates/plat_property_contexts裡面會清楚的标明是由那些檔案編譯出來的。
├── public: 平台公開政策,非平台政策是可以引用和擴充的。
├── README
├── reqd_mask: 包含了上下文中role,user的定義,裡面大部分檔案都是一些模闆,内容是空的。
├── mls
├── property_contexts
├── reqd_mask.te
├── roles
├── roles_decl
├── ......
└── users
├── seapp_contexts.mk
├── service_contexts.mk
├── tests: 測試腳本
├── tools:提供腳本和指令如checkfc檢查上下文檔案文法,sepolicy-check指令用于合并主 seapp_contexts 配置和特定裝置配置的工具,同時檢查配置的有效性
└── vendor: 非平台政策檔案,供應商可以使用的政策和上下文檔案
external/selinux:外部 SELinux 項目,用于建構主機環境中編譯 SELinux 政策和标簽所需的各種工具,如提供libselinux庫函數,checkpolicy編譯器(policy.conf編譯成cil檔案),secilc編譯器(cil檔案編譯成二進制),getenfore/setenfore指令
tree -L 1 external/selinux/
external/selinux/
├── Android.bp
├── checkpolicy : policy.conf編譯成cil檔案
├── CleanSpec.mk
├── dbus
├── gui
├── libselinux : 提供libselinux庫函數, getenfore/setenfore指令
├── libsemanage
├── libsepol: 提供檢查上下文文法的工具和庫函數。
├── Makefile
├── mcstrans
├── MODULE_LICENSE_GPL
├── NOTICE
├── OWNERS
├── policycoreutils: 提供load_policy,chcon等指令
├── prebuilts : 提供audit2allow,sediff等指令
├── python
├── README
├── README.android
├── restorecond
├── sandbox
├── scripts
├── secilc : cil檔案編譯成二進制
└── semodule-utils
BOARD_SEPOLICY_DIRS : 闆級/供應商定制或擴充的政策檔案,
一般在device/manufacturer/device-name/BoardConfig.mk中指定, 格式為:
BOARD_SEPOLICY_DIRS += device/$SoC/common/sepolicy
BOARD_SEPOLICY_DIRS += device/$SoC/$DEVICE/sepolicy
當然也有BOARD_ODM_SEPOLICY_DIRS和BOARD_ODM_SEPOLICY_DIRS分别指定odm和product分區的政策檔案。
rk3399對應的vendor seplicy檔案目錄為device/rockchip/common/sepolicy,各個産品引用如下
device/rockchip/rk3399/rk3399_roc_pc_plus/rk3399_roc_pc_plus.mk +22
include device/rockchip/common/BoardConfig.mk
# Sepolicy
PRODUCT_SEPOLICY_SPLIT := false
BOARD_SEPOLICY_DIRS ?= \
device/rockchip/common/sepolicy/vendor
BOARD_PLAT_PUBLIC_SEPOLICY_DIR ?= device/rockchip/common/sepolicy/public
BOARD_PLAT_PRIVATE_SEPOLICY_DIR ?= \
device/rockchip/common/sepolicy/private \
device/rockchip/$(TARGET_BOARD_PLATFORM)/sepolicy (實際不存在)
二, Android Selinux總體編譯邏輯
Android編譯的核心規則都是在system/sepolicy/Android.mk定義,可參考官網:
建構 SELinux 政策 | Android 開源項目 | Android Open Source Project
總體編譯步驟如下所說:
# build process for device:
# 1) convert policies to CIL: 将政策轉換為 SELinux 通用中間語言 (CIL) 格式
# - private + public platform policy to CIL
# - mapping file to CIL (should already be in CIL form)
# - non-platform public policy to CIL
# - non-platform public + private policy to CIL
# 2) attributize policy:公共政策屬性化,并将公共政策作為供應商政策的一部分進行版本控制。
# - run script which takes non-platform public and non-platform combined
# private + public policy and produces attributized and versioned
# non-platform policy
# 3) combine policy files : 合并政策檔案
# - combine mapping, platform and non-platform policy.
# - compile output binary policy file
最核心的過程就是:
te政策檔案
----transform-policy-to-conf(m4宏處理)---> 得到conf宏展開并合并檔案
----checkpolicy編譯conf檔案---------------->得到cil通用中間語言檔案
----secilc工具編譯cil檔案---------------------> 得到目标檔案precompiled_sepolicy二進制
谷歌官網建構sepolicy政策檔案的圖示:
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiI0gTMx81dsQWZ4lmZf1GLlpXazVmcvwFciV2dsQXYtJ3bm9CX9s2RkBnVHFmb1clWvB3MaVnRtp1XlBXe0xCMy81dvRWYoNHLwEzX5xCMx8FesU2cfdGLwMzX0xiRGZkRGZ0Xy9GbvNGLpZTY1EmMZVDUSFTU4VFRR9Fd4VGdsYTMfVmepNHLrJXYtJXZ0F2dvwVZnFWbp1zczV2YvJHctM3cv1Ce-cmbw5SN2cTO2ADNlRzNkNmNiJmYyYzX3UTOxATM5IzLcZDMyIDMy8CXn9Gbi9CXzV2Zh1WavwVbvNmLvR3YxUjLyM3Lc9CX6MHc0RHaiojIsJye.png)
Android.mk中指定的編譯源檔案:
詳細過程請參考大神: Android P SELinux (二) 開機初始化與政策檔案編譯過程_headwind_的部落格-CSDN部落格
Android.mk中比較常見的一個規則:
define build_policy
$(foreach type, $(1), $(foreach file, $(addsuffix /$(type), $(2)), $(sort $(wildcard $(file)))))
endef
參數2,表示一個目标目錄
參數1, 表示在目标目錄下查找的檔案名
調用:
$(call build_policy, file_contexts, $(PLAT_PRIVATE_POLICY))
表示從PLAT_PRIVATE_POLICY目錄中找出所有的file_contexts檔案