关于9.0系统Selinux权限问题报错的分析和处理

  • Post author:
  • Post category:linux




Selinux简介

SELinux是安全增强型 Linux(Security-Enhanced Linux)简称 SELinux。它是一个 Linux 内核模块,也是 Linux 的一个安全子系统。

SELinux for Android在架构和机制上与SELinux完全一样,考虑到移动设备的特点,所以移植到Android上的只是SELinux的一个子集。SELinux for Android的安全检查几乎覆盖了所有重要的系统资源,包括域转换,类型转换,进程、内核、文件、目录、设备,App,网络及IPC相关的操作。

Android分为宽容模式(仅记录但不强制执行 SELinux 安全政策 )和强制模式(强制执行并记录安全政策。如果失败,则显示为 EPERM 错误。 );在选择强制执行级别时只能二择其一。



Selinux模式:

Enforce模式:打印异常log,拒绝请求。没有权限的请求被拒绝后 执行就会有问题。

Permissive模式:打印异常log,不拒绝请求。请求没被拒绝,执行不会出现问题。



设置SELinux:

adb shell setenforce 0   //设置后即Permissive
adb shell setenforce 1   //设置后即Enforcing

这种设置,在某些版本下需要root权限。



Selinux实际报错日志

这次遇到的问题,就是软件的串口通讯问题。这个软件在debug版系统上,运行的挺好的,切换到user系统上,通讯就会失败,会遇到权限问题导致通讯失败。日志如下:

05-14 10:24:00.144 2773 2773 I test.app: type=1400 audit(0.0:1079): avc: denied { ioctl } for path="socket:[43620]" dev ="sockfs" ino=43620 ioctlcmd=0x8933 scontext=u:r:platform_app:s0:c512,c768 tcontext=u:r:platform_app:s0:c512,c768 tclass=socket permissive=0



分析

avc: denied { 操作权限 } for pid=7201 comm=“进程名” scontext=u:r:源类型:s0 tcontext=u:r:目标类型:s0 tclass=访问类别 permissive=0



添加规则

allow scontext tcontext:tclass denied



添加权限

在device/mediatek/sepolicy/bsp/non_plat/platform_app.te(备注:本项目是9.0MTK6765,请依据自己项目具体定位添加位置,一般处于system/sepolicy/

或device/qcom/sepolicy/

)中添加:

allow platform_app platform_app:socket ioctl;



实际情况

正常情况按照上面那么加权限就行啦,但是。。。

在 Android P上面由于谷歌收紧了 Android SElinux控制,增加了许多neverallow规则,导致调试权限十分不便

而ioctl就是谷歌在9.0上重点限制的部分权限。这部分就是串口和通讯相关权限。

如果直接加上面的权限,会直接报错。相关修改见此博客,讲的挺好:


Android P系统编译报错SELinux违反Neverallow



最终处理方案

别的博客里的处理方案修改代码过多,而且容易连带改出其他BUG。因为我司设备有加密芯片,限制严格,我就准备从宽容模式入手,将USER版系统的Selinux模式改为宽容模式,允许通过这部分权限,来解决问题。



源码分析

system/core/init/selinux.cpp
system/core/init/main.cpp

核心代码在俩个文件内,大概流程如下:

①:main.cpp中的main函数调用selinux.cpp中的SetupSelinux:

int main(int argc, char** argv) {

        ...省略
        if (!strcmp(argv[1], "selinux_setup")) {
            return SetupSelinux(argv);
        }
        ...省略
}

②:selinux.cpp中SetupSelinux函数实现如下:

int SetupSelinux(char** argv) {

    ...省略
    SelinuxInitialize();

    ...省略
    return 1;
}

③:SetupSelinux调用了SelinuxInitialize方法。SelinuxInitialize方法代码如下:

void SelinuxInitialize() {
    ...省略
    bool kernel_enforcing = (security_getenforce() == 1);
    //判断是否强制模式
    bool is_enforcing = IsEnforcing();
    if (kernel_enforcing != is_enforcing) {
        //调用security_setenforce函数,和setenforce原理一样
        if (security_setenforce(is_enforcing)) {
            PLOG(FATAL) << "security_setenforce(%s) failed" << (is_enforcing ? "true" : "false");
        }
    }
    ...省略
}

④:IsEnforcing方法实现如下:

bool IsEnforcing() {
    if (ALLOW_PERMISSIVE_SELINUX) {
        return StatusFromCmdline() == SELINUX_ENFORCING;
    }
    return true;
}

⑤:从IsEnforcing中可以知道,如果一直返回false,那么将会关闭selinux。



最终修改,即全局强制关闭selinux:

bool IsEnforcing() {
	if(1 > 0) {
		return false;
	}
	
	if (ALLOW_PERMISSIVE_SELINUX) {
        return StatusFromCmdline() == SELINUX_ENFORCING;
    }
    return true;
}

价格1>0的判断是因为直接return false会导致系统编译不通过,不信邪的朋友可以尝试一下。



结语

自此,这个BUG算是处理完了,又学到了很多新知识,关于Selinux,关于安卓的安全防御机制。

如果你能从这篇博客中获取到有用的东西,点个赞。



版权声明:本文为w752325717原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。