欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android selinux策略文件的編譯與加載

 更新時(shí)間:2023年03月08日 10:38:32   作者:拉普  
這篇文章主要為大家介紹了Android selinux策略文件的編譯與加載用法解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

引言

注:本文寫(xiě)于2020年,基于Android11,Android12之后代碼有些許變化,但是代碼邏輯還是沒(méi)變.

本文分析了selinux策略文件 在開(kāi)機(jī)時(shí)的加載過(guò)程.selinux文章很多,寫(xiě)這個(gè)的應(yīng)該不多.

編譯

用法1:

編譯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 目錄下

注:當(dāng)前以規(guī)則文件 vendor_sepolicy.cil 為例。

  • 備份后刪除/odm/etc/selinux/precompiled_sepolicy文件
  • 重啟手機(jī)后生效

用法2(推薦):

編譯selinux

make selinux_policy -j48

make編譯大約 3~17分鐘 如果make編譯過(guò)了,可使用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/目錄下
  • 重啟手機(jī)后生效

注:App上下文seapp_contexts,文件上下文 file_contexts ,屬性上下文 property_contexts 的修改生效方法,見(jiàn)文末

原理簡(jiǎn)介:

手機(jī)啟動(dòng)后,進(jìn)入加載selinux政策流程,會(huì)使用/odm/etc/selinux/目錄下的兩個(gè)sha256文件中的值分別同/system/etc/selinux,/product/etc/selinux 目錄的sha256文件中的值對(duì)比,如果都相等,則加載/odm/etc/selinux/目錄下的/odm/etc/selinux/precompiled_sepolicy 預(yù)編譯的selinux二進(jìn)制政策文件。如果不同,則使用/system/etc/selinux 和 /vendor/etc/selinux 等目錄下的文件重新編譯 selinux二進(jìn)制政策文件,然后加載新的 sepolicy 文件。

1、selinux政策加載流程(加載sepolicy 二進(jìn)制文件流程)

函數(shù)調(diào)用流程:

system/core/init/main.cpp

? ---> selinux.cpp ---> int SetupSelinux(char** argv)

? ---> SelinuxInitialize();

? ---> LoadPolicy()

? ---> LoadSplitPolicy()

? ---> FindPrecompiledSplitPolicy(std::string* file) // 關(guān)鍵函數(shù)

函數(shù)調(diào)用流程講解:

開(kāi)機(jī)啟動(dòng)時(shí)會(huì)加載selinux政策。main.cpp 中調(diào)用 selinux.cpp 中的 int SetupSelinux(char** argv) 函數(shù),SetupSelinux 調(diào)用SelinuxInitialize(),SelinuxInitialize() 調(diào)用 LoadPolicy() 函數(shù)

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 方法中會(huì)判斷 /system/etc/selinux/plat_sepolicy.cil 文件是否存在,存在調(diào)用LoadSplitPolicy,不存在調(diào)用LoadMonolithicPolicy方法從根目錄/sepolicy(此路徑在 /external/selinux/libselinux/src/android/android_platform.c sepolicy_file變量寫(xiě)死)下加載selinux政策(這是以前的版本)

【根據(jù)此處代碼邏輯,make sepolicy 后,把生成的文件out\target\product\klein\root\sepolicy,push到根目錄下,順便刪除/system/etc/selinux/plat_sepolicy.cil 文件

應(yīng)該也可以使新的selinux政策生效(經(jīng)測(cè)試無(wú)法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 由環(huán)境變量 INIT_FORCE_DEBUGGABLE 決定,使用adb shell命令 echo $INIT_FORCE_DEBUGGABLE 查看此變量為空,所以 use_userdebug_policy == false

代碼進(jìn)入 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 查看此環(huán)境變量的值
    // 此變量為空,所以 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 ,進(jìn)入 FindPrecompiledSplitPolicy 函數(shù)
    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));//創(chuàng)建臨時(shí)文件
    if (compiled_sepolicy_fd < 0) {
        PLOG(ERROR) << "Failed to create temporary file " << compiled_sepolicy;
        return false;
    }
	···
    unlink(compiled_sepolicy);// 臨時(shí)文件如果不再被使用后,文件會(huì)被自動(dòng)刪除
    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

對(duì)比兩個(gè)文件中的sha值

/odm/etc/selinux/precompiled_sepolicy.product_sepolicy_and_mapping.sha256

/product/etc/selinux/product_sepolicy_and_mapping.sha256

并且對(duì)比這兩個(gè)文件中的sha值

如果這兩對(duì)文件中的值一致,F(xiàn)indPrecompiledSplitPolicy返回true,不一致返回false。

如果/odm/etc/selinux/目錄下沒(méi)有precompiled_sepolicy文件,

則會(huì)去/vendor/etc/selinux/目錄下找相關(guān)的mapping.sha256去和system product 中的文件對(duì)比,

(我們的手機(jī)沒(méi)有/vendor/etc/selinux/precompiled_sepolicy文件)

如果/vendor/etc/selinux/目錄下也沒(méi)有precompiled_sepolicy文件,

則FindPrecompiledSplitPolicy返回 false。

如果FindPrecompiledSplitPolicy返回true,加載預(yù)編譯的政策

FindPrecompiledSplitPolicy返回false,則重新編譯selinux政策,完成后加載新政策

【由此,可推測(cè),修改/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;
}

2、綜上使新的selinux政策生效的方法有:

  • 刪除/system/etc/selinux/plat_sepolicy.cil 文件,make sepolicy 后,把生成的文件out\target\product\klein\root\sepolicy,push到根目錄下 【無(wú)法push:Read-only file system】
  • make selinux_policy 后,把生成的文件out\target\product\klein\odm\etc\selinux\precompiled_sepolicy,push到/odm/etc/selinux/目錄下 【已驗(yàn)證】
  • make selinux_policy 后,把生成的文件out\target\product\klein\odm\etc\selinux\precompiled_sepolicy,push到/vendor/etc/selinux/目錄下,復(fù)制/odm/etc/selinux/目錄下的兩個(gè)sha文件到/vendor/etc/selinux/目錄 【未驗(yàn)證】
  • 刪除或修改/odm/etc/selinux/precompiled_sepolicy.plat_sepolicy_and_mapping.sha256 【已驗(yàn)證 刪除方式】
  • 刪除或修改/odm/etc/selinux/precompiled_sepolicy.product_sepolicy_and_mapping.sha256 【未驗(yàn)證】
  • 刪除或修改**/system/etc/selinux/plat_sepolicy_and_mapping.sha256** 【已驗(yàn)證 修改方式】
  • 刪除或修改/product/etc/selinux/product_sepolicy_and_mapping.sha256 【已驗(yàn)證 刪除方式】
  • 刪除/odm/etc/selinux/precompiled_sepolicy文件 【已驗(yàn)證】

3、關(guān)于開(kāi)機(jī)編譯sepolicy文件

開(kāi)機(jī)時(shí)重新編譯的sepolicy文件,會(huì)編譯一個(gè)臨時(shí)文件/dev/sepolicy.XXXXXX,新的selinux生效后,此文件會(huì)被刪除。

當(dāng)前測(cè)試發(fā)現(xiàn):開(kāi)機(jī)時(shí)編譯sepolicy文件會(huì)導(dǎo)致開(kāi)機(jī)時(shí)間變長(zhǎng),并且每次開(kāi)機(jī)都編譯一次。

有沒(méi)有其他副作用?暫時(shí)未發(fā)現(xiàn)。

4、開(kāi)機(jī) SELinux 相關(guān) log

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中出現(xiàn)此日志表明在編譯新的selinux,selinux將會(huì)生效 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生效,如果沒(méi)有編譯新的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手機(jī)上。重啟后生效。
  • 屬性的上下文 property_contexts 文件, 可以直接修改,push手機(jī)上。重啟后生效。
  • 服務(wù)的上下文 service_contexts 文件,可以直接修改,push手機(jī)上。重啟后生效。
  • 虛擬文件上下文 genfs_contexts 文件,通過(guò)chcon命令進(jìn)行修改
  • 講下文件上下文 file_contexts 文件的修改與測(cè)試。restorecon 命令可使文件上下文selinux政策生效。 restorecon -R

chcon : 隨意修改某個(gè)文件(夾)的selinux lable。Ex: chcon u:object_r:system_data_file:s0 /data/app

restorecon : 依照sepolicy Rule中定義的規(guī)則,重新relable指定的文件(夾)。

修改 /system/bin/toybox 上下文示例:把junkserver的上下文修改為 shell_exec

  • 首先修改 /system/etc/selinux/plat_file_contexts 文件內(nèi)容
  • 把 /system/bin/toybox u:object_r:toolbox_exec:s0
  • 修改為: /system/bin/toybox u:object_r:shell_exec:s0

進(jìn)入手機(jī)shell 執(zhí)行以下命令

# restorecon 命令需要跟參數(shù),無(wú)法執(zhí)行單個(gè)命令
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策略文件的編譯與加載的詳細(xì)內(nèi)容,更多關(guān)于Android selinux策略編譯的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論