您好,登錄后才能下訂單哦!
本文小編為大家詳細介紹“Android selinux策略文件怎么編譯與加載”,內容詳細,步驟清晰,細節處理妥當,希望這篇“Android selinux策略文件怎么編譯與加載”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學習新知識吧。
編譯selinux
make sepolicy -j48 或 make selinux_policy -j48
把生成的文件 \out\target\product\XXXX\obj\ETC\vendor_sepolicy.cil_intermediates\vendor_sepolicy.cil push(out\target\product\XXXX\vendor\etc\selinux\vendor_sepolicy.cil)到 /vendor/etc/selinux 目錄下
注:當前以規則文件 vendor_sepolicy.cil 為例。
備份后刪除/odm/etc/selinux/precompiled_sepolicy文件
重啟手機后生效
編譯selinux
make selinux_policy -j48
make編譯大約 3~17分鐘 如果make編譯過了,可使用ninja編譯,不到一分鐘就可以編譯完成
time prebuilts/build-tools/linux-x86/bin/ninja -f out/combined-XXXX.ninja -j48 selinux_policy
time prebuilts/build-tools/linux-x86/bin/ninja -f out/combined-XXXX.ninja -j48 sepolicy.recovery
備份/odm/etc/selinux/precompiled_sepolicy文件
把生成的文件out\target\product\klein\odm\etc\selinux\precompiled_sepolicy,push到/odm/etc/selinux/目錄下
重啟手機后生效
注:App上下文seapp_contexts,文件上下文 file_contexts ,屬性上下文 property_contexts 的修改生效方法,見文末
手機啟動后,進入加載selinux政策流程,會使用/odm/etc/selinux/目錄下的兩個sha256文件中的值分別同/system/etc/selinux,/product/etc/selinux 目錄的sha256文件中的值對比,如果都相等,則加載/odm/etc/selinux/目錄下的/odm/etc/selinux/precompiled_sepolicy 預編譯的selinux二進制政策文件。如果不同,則使用/system/etc/selinux 和 /vendor/etc/selinux 等目錄下的文件重新編譯 selinux二進制政策文件,然后加載新的 sepolicy 文件。
system/core/init/main.cpp
---> selinux.cpp ---> int SetupSelinux(char** argv)
---> SelinuxInitialize();
---> LoadPolicy()
---> LoadSplitPolicy()
---> FindPrecompiledSplitPolicy(std::string* file) // 關鍵函數
開機啟動時會加載selinux政策。main.cpp 中調用 selinux.cpp 中的 int SetupSelinux(char** argv) 函數,SetupSelinux 調用SelinuxInitialize(),SelinuxInitialize() 調用 LoadPolicy() 函數
int SetupSelinux(char** argv) { ··· // Set up SELinux, loading the SELinux policy. SelinuxSetupKernelLogging(); SelinuxInitialize(); ··· return 1; }
void SelinuxInitialize() { ··· LOG(INFO) << "Loading SELinux policy"; if (!LoadPolicy()) { LOG(FATAL) << "Unable to load SELinux policy"; } ··· }
LoadPolicy 方法中會判斷 /system/etc/selinux/plat_sepolicy.cil 文件是否存在,存在調用LoadSplitPolicy,不存在調用LoadMonolithicPolicy方法從根目錄/sepolicy(此路徑在 /external/selinux/libselinux/src/android/android_platform.c sepolicy_file變量寫死)下加載selinux政策(這是以前的版本)
【根據此處代碼邏輯,make sepolicy 后,把生成的文件out\target\product\klein\root\sepolicy,push到根目錄下,順便刪除/system/etc/selinux/plat_sepolicy.cil 文件
應該也可以使新的selinux政策生效(經測試無法push到根目錄:Read-only file system)】
bool LoadPolicy() { return IsSplitPolicyDevice() ? LoadSplitPolicy() : LoadMonolithicPolicy(); } constexpr const char plat_policy_cil_file[] = "/system/etc/selinux/plat_sepolicy.cil"; bool IsSplitPolicyDevice() { return access(plat_policy_cil_file, R_OK) != -1; } bool LoadMonolithicPolicy() { LOG(VERBOSE) << "Loading SELinux policy from monolithic file"; if (selinux_android_load_policy() < 0) { PLOG(ERROR) << "Failed to load monolithic SELinux policy"; return false; } return true; }
/external/selinux/libselinux/src/android/android_platform.c
static const char *const sepolicy_file = "/sepolicy"; int selinux_android_load_policy() { int fd = -1; fd = open(sepolicy_file, O_RDONLY | O_NOFOLLOW | O_CLOEXEC); if (fd < 0) { selinux_log(SELINUX_ERROR, "SELinux: Could not open %s: %s\n", sepolicy_file, strerror(errno)); return -1; } int ret = selinux_android_load_policy_from_fd(fd, sepolicy_file); close(fd); return ret; }
LoadSplitPolicy() 方法
use_userdebug_policy 由環境變量 INIT_FORCE_DEBUGGABLE 決定,使用adb shell命令 echo $INIT_FORCE_DEBUGGABLE 查看此變量為空,所以 use_userdebug_policy == false
代碼進入 FindPrecompiledSplitPolicy方法.
bool LoadSplitPolicy() { // IMPLEMENTATION NOTE: Split policy consists of three CIL files: // * platform -- policy needed due to logic contained in the system image, // * non-platform -- policy needed due to logic contained in the vendor image, // * mapping -- mapping policy which helps preserve forward-compatibility of non-platform policy // with newer versions of platform policy. // // secilc is invoked to compile the above three policy files into a single monolithic policy // file. This file is then loaded into the kernel. // See if we need to load userdebug_plat_sepolicy.cil instead of plat_sepolicy.cil. const char* force_debuggable_env = getenv("INIT_FORCE_DEBUGGABLE"); // 可使用adb shell命令 echo $INIT_FORCE_DEBUGGABLE 查看此環境變量的值 // 此變量為空,所以 use_userdebug_policy == false bool use_userdebug_policy = ((force_debuggable_env && "true"s == force_debuggable_env) && AvbHandle::IsDeviceUnlocked() && access(kDebugRamdiskSEPolicy, F_OK) == 0); if (use_userdebug_policy) { LOG(WARNING) << "Using userdebug system sepolicy"; } // Load precompiled policy from vendor image, if a matching policy is found there. The policy // must match the platform policy on the system image. std::string precompiled_sepolicy_file; // use_userdebug_policy requires compiling sepolicy with userdebug_plat_sepolicy.cil. // Thus it cannot use the precompiled policy from vendor image. // 核心代碼 !use_userdebug_policy == true ,進入 FindPrecompiledSplitPolicy 函數 if (!use_userdebug_policy && FindPrecompiledSplitPolicy(&precompiled_sepolicy_file)) { unique_fd fd(open(precompiled_sepolicy_file.c_str(), O_RDONLY | O_CLOEXEC | O_BINARY)); if (fd != -1) { if (selinux_android_load_policy_from_fd(fd, precompiled_sepolicy_file.c_str()) < 0) { LOG(ERROR) << "Failed to load SELinux policy from " << precompiled_sepolicy_file; return false; } return true; } } // No suitable precompiled policy could be loaded LOG(INFO) << "Compiling SELinux policy"; // We store the output of the compilation on /dev because this is the most convenient tmpfs // storage mount available this early in the boot sequence. char compiled_sepolicy[] = "/dev/sepolicy.XXXXXX"; unique_fd compiled_sepolicy_fd(mkostemp(compiled_sepolicy, O_CLOEXEC));//創建臨時文件 if (compiled_sepolicy_fd < 0) { PLOG(ERROR) << "Failed to create temporary file " << compiled_sepolicy; return false; } ··· unlink(compiled_sepolicy);// 臨時文件如果不再被使用后,文件會被自動刪除 LOG(INFO) << "Loading compiled SELinux policy"; // 編譯完成,加載新的selinux文件 if (selinux_android_load_policy_from_fd(compiled_sepolicy_fd, compiled_sepolicy) < 0) { LOG(ERROR) << "Failed to load SELinux policy from " << compiled_sepolicy; return false; } return true; }
FindPrecompiledSplitPolicy 此方法主要工作:
/odm/etc/selinux/precompiled_sepolicy.plat_sepolicy_and_mapping.sha256
/system/etc/selinux/plat_sepolicy_and_mapping.sha256
對比兩個文件中的sha值
/odm/etc/selinux/precompiled_sepolicy.product_sepolicy_and_mapping.sha256
/product/etc/selinux/product_sepolicy_and_mapping.sha256
并且對比這兩個文件中的sha值
如果這兩對文件中的值一致,FindPrecompiledSplitPolicy返回true,不一致返回false。
如果/odm/etc/selinux/目錄下沒有precompiled_sepolicy文件,
則會去/vendor/etc/selinux/目錄下找相關的mapping.sha256去和system product 中的文件對比,
(我們的手機沒有/vendor/etc/selinux/precompiled_sepolicy文件)
如果/vendor/etc/selinux/目錄下也沒有precompiled_sepolicy文件,
則FindPrecompiledSplitPolicy返回 false。
如果FindPrecompiledSplitPolicy返回true,加載預編譯的政策
FindPrecompiledSplitPolicy返回false,則重新編譯selinux政策,完成后加載新政策
【由此,可推測,修改/odm/etc/selinux/precompiled_sepolicy.plat_sepolicy_and_mapping.sha256文件中的值,
或,修改/odm/etc/selinux/precompiled_sepolicy.product_sepolicy_and_mapping.sha256的值
或,修改/system/etc/selinux/plat_sepolicy_and_mapping.sha256的值
或,修改/product/etc/selinux/product_sepolicy_and_mapping.sha256的值
或,刪除/odm/etc/selinux/precompiled_sepolicy文件
都能引起重啟后,重新編譯新的sepolicy文件,使新的selinux政策生效】
bool FindPrecompiledSplitPolicy(std::string* file) { file->clear(); // If there is an odm partition, precompiled_sepolicy will be in // odm/etc/selinux. Otherwise it will be in vendor/etc/selinux. static constexpr const char vendor_precompiled_sepolicy[] = "/vendor/etc/selinux/precompiled_sepolicy"; static constexpr const char odm_precompiled_sepolicy[] = "/odm/etc/selinux/precompiled_sepolicy"; if (access(odm_precompiled_sepolicy, R_OK) == 0) { *file = odm_precompiled_sepolicy; } else if (access(vendor_precompiled_sepolicy, R_OK) == 0) { *file = vendor_precompiled_sepolicy; } else { PLOG(INFO) << "No precompiled sepolicy"; return false; } std::string actual_plat_id; if (!ReadFirstLine("/system/etc/selinux/plat_sepolicy_and_mapping.sha256", &actual_plat_id)) { PLOG(INFO) << "Failed to read " "/system/etc/selinux/plat_sepolicy_and_mapping.sha256"; return false; } std::string actual_product_id; if (!ReadFirstLine("/product/etc/selinux/product_sepolicy_and_mapping.sha256", &actual_product_id)) { PLOG(INFO) << "Failed to read " "/product/etc/selinux/product_sepolicy_and_mapping.sha256"; return false; } std::string precompiled_plat_id; std::string precompiled_plat_sha256 = *file + ".plat_sepolicy_and_mapping.sha256"; if (!ReadFirstLine(precompiled_plat_sha256.c_str(), &precompiled_plat_id)) { PLOG(INFO) << "Failed to read " << precompiled_plat_sha256; file->clear(); return false; } std::string precompiled_product_id; std::string precompiled_product_sha256 = *file + ".product_sepolicy_and_mapping.sha256"; if (!ReadFirstLine(precompiled_product_sha256.c_str(), &precompiled_product_id)) { PLOG(INFO) << "Failed to read " << precompiled_product_sha256; file->clear(); return false; } // 核心代碼 if (actual_plat_id.empty() || actual_plat_id != precompiled_plat_id || actual_product_id.empty() || actual_product_id != precompiled_product_id) { file->clear(); return false; } return true; }
刪除/system/etc/selinux/plat_sepolicy.cil 文件,make sepolicy 后,把生成的文件out\target\product\klein\root\sepolicy,push到根目錄下 【無法push:Read-only file system】
make selinux_policy 后,把生成的文件out\target\product\klein\odm\etc\selinux\precompiled_sepolicy,push到/odm/etc/selinux/目錄下 【已驗證】
make selinux_policy 后,把生成的文件out\target\product\klein\odm\etc\selinux\precompiled_sepolicy,push到/vendor/etc/selinux/目錄下,復制/odm/etc/selinux/目錄下的兩個sha文件到/vendor/etc/selinux/目錄 【未驗證】
刪除或修改/odm/etc/selinux/precompiled_sepolicy.plat_sepolicy_and_mapping.sha256 【已驗證 刪除方式】
刪除或修改/odm/etc/selinux/precompiled_sepolicy.product_sepolicy_and_mapping.sha256 【未驗證】
刪除或修改**/system/etc/selinux/plat_sepolicy_and_mapping.sha256** 【已驗證 修改方式】
刪除或修改/product/etc/selinux/product_sepolicy_and_mapping.sha256 【已驗證 刪除方式】
刪除/odm/etc/selinux/precompiled_sepolicy文件 【已驗證】
開機時重新編譯的sepolicy文件,會編譯一個臨時文件/dev/sepolicy.XXXXXX,新的selinux生效后,此文件會被刪除。
當前測試發現:開機時編譯sepolicy文件會導致開機時間變長,并且每次開機都編譯一次。
有沒有其他副作用?暫時未發現。
1970-01-01 11:56:20.738 0-0/? I/SELinux: Initializing. 1970-01-01 11:56:31.265 0-0/? I/init: Loading SELinux policy 1970-01-01 11:56:31.271 0-0/? I/init: Compiling SELinux policy // log中出現此日志表明在編譯新的selinux,selinux將會生效 1970-01-01 11:56:32.034 0-0/? I/init: Loading compiled SELinux policy1970-01-01 11:56:32.255 0-0/? I/SELinux: policy capability network_peer_controls=1 1970-01-01 11:56:32.255 0-0/? I/SELinux: policy capability open_perms=1 1970-01-01 11:56:32.255 0-0/? I/SELinux: policy capability extended_socket_class=1 1970-01-01 11:56:32.255 0-0/? I/SELinux: policy capability always_check_network=0 1970-01-01 11:56:32.255 0-0/? I/SELinux: policy capability cgroup_seclabel=0 1970-01-01 11:56:32.255 0-0/? I/SELinux: policy capability nnp_nosuid_transition=1 1970-01-01 11:56:32.461 0-0/? I/selinux: SELinux: Loaded policy from /dev/sepolicy.ys2KNm // 新的selinux生效,如果沒有編譯新的selinux,此處加載的是/odm/etc/selinux/precompiled_sepolicy 1970-01-01 11:56:32.467 0-0/? W/selinux: SELinux: Skipping /product/etc/selinux/product_file_contexts: empty file 1970-01-01 11:56:32.467 0-0/? I/selinux: SELinux: Loaded file_contexts 1970-01-01 11:56:32.524 0-0/? W/selinux: SELinux: Skipping /product/etc/selinux/product_file_contexts: empty file 1970-01-01 11:56:32.524 0-0/? I/selinux: SELinux: Loaded file_contexts
App的上下文 seapp_contexts 文件,可以直接修改,push手機上。重啟后生效。
屬性的上下文 property_contexts 文件, 可以直接修改,push手機上。重啟后生效。
服務的上下文 service_contexts 文件,可以直接修改,push手機上。重啟后生效。
虛擬文件上下文 genfs_contexts 文件,通過chcon命令進行修改
講下文件上下文 file_contexts 文件的修改與測試。restorecon 命令可使文件上下文selinux政策生效。 restorecon -R
chcon : 隨意修改某個文件(夾)的selinux lable。Ex: chcon u:object_r:system_data_file:s0 /data/app
restorecon : 依照sepolicy Rule中定義的規則,重新relable指定的文件(夾)。
修改 /system/bin/toybox 上下文示例:把junkserver的上下文修改為 shell_exec
首先修改 /system/etc/selinux/plat_file_contexts 文件內容
把 /system/bin/toybox u:object_r:toolbox_exec:s0
修改為: /system/bin/toybox u:object_r:shell_exec:s0
進入手機shell 執行以下命令
# restorecon 命令需要跟參數,無法執行單個命令 mobius:/ # restorecon system/bin/toybox -v SELinux: Skipping /product/etc/selinux/product_file_contexts: empty file SELinux: Loaded file_contexts SELinux: Relabeling /system/bin/toybox from u:object_r:toolbox_exec:s0 to u:object_r:shell_exec:s0.
可以看到文件上下文生效了
mobius:/ # ls system/bin/toybox -lZ -rwxrwxrwx 1 root shell u:object_r:shell_exec:s0 432976 2009-01-01 08:00 system/bin/toybox
chcon
# android chcon <安全上下文> 文件 chcon -R <安全上下文> 目錄 # 示例 klein:/ # chcon -v u:object_r:junkserverd_d_file:s0 /data/junk-server/junk.txt chcon '/data/junk-server/junk.txt' to u:object_r:junkserverd_d_file:s0 # chcon -R -v u:object_r:system_data_file:s0 ./0 # linux: chcon -t <安全上下文> 文件 chcon -R -t <安全上下文> 目錄
讀到這里,這篇“Android selinux策略文件怎么編譯與加載”文章已經介紹完畢,想要掌握這篇文章的知識點還需要大家自己動手實踐使用過才能領會,如果想了解更多相關內容的文章,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。