• Android 11源码——安全策略SELinux关闭


    Android 11源码 安全策略SELinux关闭

    SELinux介绍

    作为 Android 安全模型的一部分,Android 使用安全增强型 Linux (SELinux) 对所有进程强制执行强制访问控制 (MAC),甚至包括以 Root/超级用户权限运行的进程(Linux 功能)。借助 SELinux,Android 可以更好地保护和限制系统服务、控制对应用数据和系统日志的访问、降低恶意软件的影响,并保护用户免遭移动设备上的代码可能存在的缺陷的影响。

    SELinux 按照默认拒绝的原则运行:任何未经明确允许的行为都会被拒绝。SELinux 可按两种全局模式运行:

    1. 宽容模式:权限拒绝事件会被记录下来,但不会被强制执行。
    2. 强制模式:权限拒绝事件会被记录下来并强制执行。

    Android 中包含 SELinux(处于强制模式)和默认适用于整个 AOSP 的相应安全政策。在强制模式下,非法操作会被阻止,并且尝试进行的所有违规行为都会被内核记录到 dmesg 和 logcat。开发时,您应该先利用这些错误信息对软件和 SELinux 政策进行优化,再对它们进行强制执行。

    此外,SELinux 还支持基于域的宽容模式。在这种模式下,可将特定域(进程)设为宽容模式,同时使系统的其余部分处于全局强制模式。简单来说,域是安全政策中用于标识一个进程或一组进程的标签,安全政策会以相同的方式处理所有具有相同域标签的进程。借助基于域的宽容模式,可逐步将 SELinux 应用于系统中越来越多的部分,还可以为新服务制定政策(同时确保系统的其余部分处于强制模式)。

    背景

    Android 安全模型部分基于应用沙盒的概念。每个应用都在自己的沙盒内运行。在 Android 4.3 之前的版本中,这些沙盒是通过为每个应用创建独一无二的 Linux UID(在应用安装时创建)来定义的。Android 4.3 及更高版本使用 SELinux 进一步定义 Android 应用沙盒的边界。

    基于 Android 4.3(宽容模式)和 Android 4.4(部分强制模式),在 Android 5.0 及更高版本中,已全面强制执行 SELinux。通过此项变更,Android 已从对有限的一组关键域(installd、netd、vold 和 zygote)强制执行 SELinux 转为对所有域(超过 60 个)强制执行 SELinux。具体而言:

    • 在 Android 5.x 及更高版本中,所有域均处于强制模式。
    • init 以外的任何进程都不应在 init 域中运行。
    • 出现任何常规拒绝事件(对于 block_device、socket_device、default_service),都表示设备需要一个特殊域。

    Android 6.0 通过降低我们政策的宽容度强化了系统安全,从而实现更好的用户隔离和 IOCTL 过滤、降低可从设备/系统之外访问的服务面临的威胁、进一步强化 SELinux 域,以及高度限制对 /proc 的访问。

    Android 7.0 更新了 SELinux 配置,以进一步锁定应用沙盒并缩小受攻击面。此版本还将单片式 mediaserver 堆栈拆分为较小的进程,以缩小其权限范围。

    Android 8.0 更新了 SELinux 以便与 Treble 配合使用,后者可将较低级别的供应商代码与 Android 系统框架分离开来。此版本更新了 SELinux 政策以允许设备制造商和 SOC 供应商更新自己的政策部分、构建自己的映像(vendor.img、boot.img 等),然后更新这些映像而不受平台影响,反之亦然。

    虽然可以在设备上运行更高/更新版本的平台(框架),但反之并不成立;供应商映像 (vendor.img/odm.img) 的版本不能高于平台 (system.img) 的版本。因此,较新版平台可能会带来 SELinux 兼容性问题,因为平台 SELinux 政策的版本要比该政策的供应商 SELinux 部分更新。Android 8.0 模型提供了一种保持兼容性的方法,以免进行不必要的同时 OTA。

    关闭Android的SELinux

    为什么需要关闭:
    由于应用层访问设备节点的时候,因为selinux权限问题而访问不了,所以就先关闭selinux

    查看当前样机的SELinux状态值:

    adb shell getenforce
    
    • 1

    Enforcing:表示SELinux处于开启状态;
    Permissive:表示SELinux处于关闭状态。

    临时关闭

    临时关闭SELinux操作比较简单,但是前提是样机能被root,setenforce 命令修改的是 /sys/fs/selinux/enforce 节点的值,是 kernel 意义上的修改 selinux 的策略。

    adb root
    adb shell setenforce 0    // 开SELinux:设置成模式permissive    
    adb shell setenforce 1    // 关SELinux:设置成模式enforce    
    
    • 1
    • 2
    • 3
    XXX:/ # getenforce   // 获取当前SELinux状态
    Enforcing
    XXX:/ #  setenforce 0   // 临时关闭SELinux状态
    XXX:/ # getenforce   	// 获取SELinux状态
    Permissive
    XXX:/ # setenforce 1   // 永久开启SELinux状态
    XXX:/ # getenforce
    Enforcing
    XXX:/ #
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    注意点:

    • 该方式仅适用于 userdebug 版本,系统重启修改会失效
    • root 模式下运行,且必须是终端没有对setenforce进行限制,否则会报如下的错误:
    setenforce: Couldn't set enforcing status to '0': Permission denied   //非root情况
    
    • 1

    永久关闭

    init进程是Android内核启动的第一个用户级进程,其中的SELinux也是在init进程中启动的,代码位置在system/core/init/init.cpp中:

    main()方法中调用SelinuxInitialize();方法对selinux进行初始化,该方法的实现位于system/core/init/selinux.cpp中:

    int main(int argc, char** argv) {
    	...
    	SelinuxInitialize();
    	...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    init会通过security_getenforce()和selinux_is_enforcing()的值是否一致来判断是否开启SELinux,当不一致的时候会设置security_setenforce的值为is_enforcing。

    void SelinuxInitialize() {
        Timer t;
    
        LOG(INFO) << "Loading SELinux policy";
        if (!LoadPolicy()) {
            LOG(FATAL) << "Unable to load SELinux policy";
        }
    
        bool kernel_enforcing = (security_getenforce() == 1);
        bool is_enforcing = IsEnforcing();
        if (kernel_enforcing != is_enforcing) {
            if (security_setenforce(is_enforcing)) {
                PLOG(FATAL) << "security_setenforce(%s) failed" << (is_enforcing ? "true" : "false");
            }
        }
    
        if (auto result = WriteFile("/sys/fs/selinux/checkreqprot", "0"); !result) {
            LOG(FATAL) << "Unable to write to /sys/fs/selinux/checkreqprot: " << result.error();
        }
    
        // init's first stage can't set properties, so pass the time to the second stage.
        setenv("INIT_SELINUX_TOOK", std::to_string(t.duration().count()).c_str(), 1);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    /selinux.cpp文件中IsEnforcing()方法中直接返回false就是关闭selinux权限了。

    bool IsEnforcing() {
        //if (ALLOW_PERMISSIVE_SELINUX) {
        //    return StatusFromCmdline() == SELINUX_ENFORCING;
        //}
        //return true;
        return false;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    参考:
    https://source.android.google.cn/security/selinux?hl=zh-cn
    https://blog.csdn.net/wq892373445/article/details/120823080
    https://blog.csdn.net/tkwxty/article/details/103938287?spm=1001.2101.3001.6650.2&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-2.pc_relevant_paycolumn_v3&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-2.pc_relevant_paycolumn_v3&utm_relevant_index=5
    https://www.jianshu.com/p/f1a6f248c607
    https://blog.csdn.net/u012932409/article/details/114632885

  • 相关阅读:
    844. Backspace String Compare
    Hadoop的第三大组成:YARN框架
    命令行远程操作windows
    在Spring Boot API Gateway中实现Sticky Session
    手把手带你学python—牛客网python 机器学习 使用梯度下降对逻辑回归进行训练
    【推理框架】MNN框架 C++、Python、Java使用例子 Demo
    会员管理系统编程教学编程工具下载
    差分详解(附加模板和例题)
    Python简单数据清洗
    CAD重复圆绘制机械图形
  • 原文地址:https://blog.csdn.net/tracydragonlxy/article/details/124150418