selinux label的初始化过程

本文详细解析了Android系统启动过程中selinux label的初始化步骤,包括sepolicy文件的编译、加载到内核、静态文件的security context标识,以及在kernel中如何建立对象的security context。通过selinux初始化,系统确保了进程和文件的安全上下文,为后续的文件访问和进程安全管理提供基础。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

selinux的架构中主要分为:subject和object。subject可以认为是进程,object可以认为是文件(linux中一切皆文件)。在系统代码中,通过撰写sepolicy规则文件(.te),在编译阶段预先为每个关键(subject)进程设置了security context,也为object(文件)设置了security context。那么这些文件是如何生效的呢?
第一步:静态sepolicy文件之间不存在冲突,能正常编译通过;
第二步:编译阶段把sepolicy文件编译成binary文件,并传入到内核;
第三步:内核在启动后以传入的sepolicy文件为原材料,构建起selinux在kernel层的工作框架。

默认第一步已经完成的情况下,重点讨论第二步和第三步的工作流程。
sepolicy文件编译到rom里面后,会保存在rom的某个位置,然后在启动阶段把这个文件传入到kernel中。为了完成这一步需要做以下几个步骤:
1)找到selinuxfs挂载点,一般在/sys/fs/selinux,然后把这个文件写入到该目录下的load文件中;
2)然后导入selinux context文件,加载其中定义的object(文件)的security context;

system/core/init/init.cpp

545int main(int argc, char** argv) {
546    ...
564    bool is_first_stage = (getenv("INIT_SECOND_STAGE") == nullptr);
565
566    if (is_first_stage) {
567    ...
586        mount("sysfs", "/sys", "sysfs", 0, NULL);
587        mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL);
588        ...
618        // Enable seccomp if global boot option was passed (otherwise it is enabled in zygote).
619        global_seccomp();
620
621        // Set up SELinux, loading the SELinux policy.
622        SelinuxSetupKernelLogging();
623        SelinuxInitialize();
624
625        // We're in the kernel domain, so re-exec init to transition to the init domain now
626        // that the SELinux policy has been loaded.
627        if (selinux_android_restorecon("/init", 0) == -1) {
628            PLOG(FATAL) << "restorecon failed of /init failed";
629        }
630
631        setenv("INIT_SECOND_STAGE", "true", 1);
632        ...
644    }
645
646    ...
683    // Now set up SELinux for second stage.
684    SelinuxSetupKernelLogging();
685    SelabelInitialize();
686    SelinuxRestoreContext();
687    ...

其中上述代码中SelinuxInitialize函数完成把规则文件导入到/sys/fs/selinux/dload中,流程如下:
SelinuxInitialize=>LoadPolicy=>LoadSplitPolicy=>FindPrecompiledSplitPolicy=>selinux_android_load_policy_from_fd。代码实现如下:
system/core/init/selinux.cpp

201bool FindPrecompiledSplitPolicy(std::string* file) {
202    file->clear();
203    // If there is an odm partition, precompiled_sepolicy will be in
204    // odm/etc/selinux. Otherwise it will be in vendor/etc/selinux.
205    static constexpr const char vendor_precompiled_sepolicy[] =
206        "/vendor/etc/selinux/precompiled_sepolicy";
207    static constexpr const char odm_precompiled_sepolicy[] =
208        "/odm/etc/selinux/precompiled_sepolicy";
209    if (access(odm_precompiled_sepolicy, R_OK) == 0) {
210        *file = odm_precompiled_sepolicy;
211    } else if (access(vendor_precompiled_sepolicy, R_OK) == 0) {
212        *file = vendor_precompiled_sepolicy;
213    } else {
214        PLOG(INFO) << "No precompiled sepolicy";
215        return false;
216    }
217    std::string actual_plat_id;
218    if (!ReadFirstLine("/system/etc/selinux/plat_and_mapping_sepolicy.cil.sha256", &actual_plat_id)) {
219        PLOG(INFO) << "Failed to read "
220                      "/system/etc/selinux/plat_and_mapping_sepolicy.cil.sha256";
221        return false;
222    }
223
224    std::string precompiled_plat_id;
225    std::string precompiled_sha256 = *file + ".plat_and_mapping.sha256";
226    if (!ReadFirstLine(precompiled_sha256.c_str(), &precompiled_plat_id)) {
227        PLOG(INFO) << "Failed to read " << precompiled_sha256;
228        file->clear();
229        return false;
230    }
231    if ((actual_plat_id.empty()) || (actual_plat_id != precompiled_plat_id)) {
232        file->clear();
233        return false;
234    }
235    return true;
236}
...
252bool IsSplitPolicyDevice() {
253    return access(plat_policy_cil_file, R_OK) != -1;
254}
255
256bool LoadSplitPolicy() {
257    // IMPLEMENTATION NOTE: Split policy consists of three CIL files:
258    // * platform -- policy needed due to logic contained in the system image,
259    // * non-platform -- policy needed due to logic contained in the vendor image,
260    // * mapping -- mapping policy which helps preserve forward-compatibility of non-platform policy
261    //   with newer versions of platform policy.
262    //
263    // secilc is invoked to compile the above three policy files into a single monolithic policy
264    // file. This file is then loaded into the kernel.
265
266    // Load precompiled policy from vendor image, if a matching policy is found there. The policy
267    // must match the platform policy on the system image.
268    std::string precompiled_sepolicy_file;
269    if (FindPrecompiledSplitPolicy(&precompiled_sepolicy_file)) {
270        unique_fd fd(open(precompiled_sepolicy_file.c_str(), O_RDONLY | O_CLOEXEC | O_BINARY));
271        if (fd != -1) {
272            if (selinux_android_load_policy_from_fd(fd, precompiled_sepolicy_file.c_str()) < 0) {
273                LOG(ERROR) << "Failed to load SELinux policy from " << precompiled_sepolicy_file;
274                return false;
275            }
276            return true;
277        }
278    }
367}
...
378bool LoadPolicy() {
379    return IsSplitPolicyDevice() ? LoadSplitPolicy() : LoadMonolithicPolicy();
380}
...
384void SelinuxInitialize() {
385    Timer t;
386
387    LOG(INFO) << "Loading SELinux policy";
388    if (!LoadPolicy()) {
389        LOG(FATAL) << "Unable to load SELinux policy";
390    }
391    ...
400    if (auto result = WriteFile("/sys/fs/selinux/checkreqprot", "0"); !result) {
401        LOG(FATAL) << "Unable to write to /sys/fs/selinux/checkreqprot: " << result.error();
402    }
403}

然后通过SelabelInitialize()和SelinuxRestoreContext()把系统中的selinux context文件,加载其中定义的object(文件)的security context。
其中SelabelInitialize的函数中完成了两个步骤:
1)首

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值