SELinux简介和解决方法

网络参考资料:
 
SELinux(Security-Enhanced Linux)是由美国国家安全局(NSA)开发的一种强制访问控制机制。它主要整合在 Linux 内核当中,是针对特定的进程与指定的文件资源进行权限控制的系统。主要是增强传统 Linux 操作系统的安全性,并解决传统 Linux 系统中自主访问控制(DAC)系统中的各种权限问题(如 root 权限过高等)。
 

一、DAC(自主访问控制)

DAC全称为:Discretionary Access Control
DAC 是传统 UNIX 和 Linux 系统的访问控制模型,它基于用户对资源的拥有权和权限。在 DAC 模型下,用户拥有对自己创建的文件和目录的完全控制权,可以自由设置文件的访问权限(读、写、执行)以及共享权限(用户组、其他用户)。
 
ls -l显示文件的属性前面的10个字符就代表了Linux对改文件的访问控制
 

二、MAC(强制访问控制)

MAC全称为Mandatory Access Control
MAC 是在 DAC 模型之上的一个额外的安全层,它强制施加系统管理员定义的访问策略,以确保系统资源的安全性。在 Android 中,SELinux 是实现 MAC 的主要机制之一。与 DAC 不同,MAC 不允许用户或进程直接设置或修改对象的访问策略,而是由系统管理员通过 SELinux 策略文件来配置访问规则。
Android系统SELinux的两种工作模式:
1. Permissive工作模式(宽容模式)
2. Enforcing工作模式(强制模式)
 

三、基本概念

1、主体(subject)     基本等同于进程
2. 客体(object)                   被主体访问的资源:文件(含可执行文件),目录,节点等
3. 安全上下文(secure context)
ls -Z      // 显示文件(如果是目录则显示其路径下的文件)的安全上下文
ps -eZ   // 显示进程的安全上下文
Id -Z    // 可以显示shell的安全上下文

 

安全上下文格式:
举例:u:object_r:system_file:s0

user:role:type[:range] 
user:用户;
role:角色,一个user可以有多个role,不通的role拥有不同的权限
type:主体or客体的类型;
range:说是跟MLS有关,简单点说,MLS将系统的    进程和文件进行了分级,不同级别的资源需要对应级别的进程才能访问。

 

四、策略规则语句格式

allow domains types:classes permissions;

- Domain - 一个进程或一组进程的标签。也称为域类型,因为它只是指进程的类型。
- Type - 一个对象(例如,文件、套接字)或一组对象的标签
- Class - 要访问的对象(例如,文件、套接字)的类型。
- Permission - 要执行的操作(例如,读取、写入)。跟~可以将两个操作联合起来 (如:allow unconfineddomain {fs_type dev_type file_type}:{ chr_file file }~{entrypoint relabelto};)

= allow : 允许主体对客体进行操作
= neverallow :拒绝主体对客体进行操作
= dontaudit : 表示不记录某条违反规则的决策信息
= auditallow :记录某项决策信息,通常 SElinux 只记录失败的信息,应用这条规则后会记录成功的决策信息。

= class可见system/sepolicy/private/security_classes中的定义
# file-related classesclass filesystem
class file  #代表普通文件
class dir   #代表目录
class fd    #代表文件描述符
class lnk_file  #代表链接文件
class chr_file  #代表字符设备文件

# network-related classes
class socket   #socket
class tcp_socket
class udp_socket

......
class binder   #Android 平台特有的 binder
class zygote   #Android 平台特有的 zygote

= permissions可见system/sepolicy/private/access_vectors
其中inherits表示继承了某个common定义的权限
 

五、类型type

#type命令的完整格式为:type type_id [alias alias_id,] [attribute_id]

#其中,方括号中的内容为可选。alias指定了type的别名,可以指定多个别名。

#下面这个例子定义了一个名为shell的type,它和一个名为domain的属性(attribute)关联
type shell, domain; #本例来自shell.te,注意,可以关联多个attribute
sepolicy 现在分为多个部分:
public - 非平台策略开发人员可以在其上编写的导出策略附加政策。类型和属性被版本化并包含在下发非平台政策,与平台政策相结合。
private - 平台功能所需的仅平台策略,但不会导出给供应商策略开发人员,因此可能不会假设存在。
vendor - 供应商功能所需的仅限供应商策略。这个政策可以参考公共政策,但不能参考私人政策。这策略适用于从核心/非供应商树生成的组件,并且放入供应商分区。
 

SELinux解决办法:

adb shell getenforce 可查看设备selinux模式
adb shell setenforce 可设置设备selinux模式(0:permissive;1:enforcing)
 te文件一般存在于system/sepolicy/,device/qcom/sepolicy/,external/selinux以及某些三方厂商自己预置的te文件(不好定位具体路径),一般在device/qcom/sepolicy/(generic|legacy)/路径下去添加selinux规则
 

1、可以关闭SELinux

修改system/core/init/selinux.cpp文件:
b shell getenforce 可查看设备selinux模式
adb shell setenforce 可设置设备selinux模式(0:permissive;1:enforcing)
 te文件一般存在于system/sepolicy/,device/qcom/sepolicy/,external/selinux以及某些三方厂商自己预置的te文件(不好定位具体路径),一般我们在device/qcom/sepolicy/(generic|legacy)/路径下去添加selinux规则

1、可以关闭SELinux
修改system/core/init/selinux.cpp文件:
EnforcingStatus StatusFromCmdline() {
    EnforcingStatus status = SELINUX_PERMISSIVE;    // ******

    import_kernel_cmdline(false,
                          [&](const std::string& key, const std::string& value, bool in_qemu) {
                              if (key == "androidboot.selinux" && value == "permissive") {
                                  status = SELINUX_PERMISSIVE;
                              }
                          });

    return status;
}

bool IsEnforcing() { 
    return false;            // ******
    if (IsUserBuild()) {
        if (RootValueFromCmdline())
            return false;
        else
            return true;
    }

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

2、手动添加权限

一般权限问题都会在log文件中打印,可通过过滤avc关键字查看,如下:
auditd  : type=1400 audit(0.0:1275): avc: denied { open } for comm="monitor-thread" 
path="/sys/devices/platform/soc/1c08000.qcom,pcie/pci0001:00/0001:00:00.0/0001:01:00.0/net/eth0/operstate" dev="sysfs" ino=63866 
scontext=u:r:system_app:s0 tcontext=u:object_r:sysfs:s0 tclass=file permissive=1
分析过程:
哪个进程缺少权限:monitor-thread
缺少什么权限: { open}权限,
谁缺少权限: u:r:system_app:s0
对哪个文件缺少权限:u:object_r:sysfs:s0
什么类型的文件: file
完整的意思: monitor-thread(system_app)进程对sysfs类型的file缺少open权限。
接下来只需要在system_app.te文件中加入:
allow system_app sysfs:file open即可(全编译会报错,因为这句代码是给所有system_app进程开放了所有文件的open权限)
 

3、使用audit2allow工具添加规则

在ubuntu下执行:adb shell dmesg |grep avc > avc;audit2allow -i avc,例:
0
直接把规则复制粘贴到对应的te文件中(如上图应该将规则粘贴于system_app.te文件中)
有时候avc denied的log不是一次性暴露所有权限问题,要等解决一个权限问题之后,才会暴露另外一个权限问题。比如提示缺少某个目录的read权限,加入read之后,才显示缺少write权限,要一次次一次试,一次一次加,时间成本极大。
针对dir缺少的任何权限,建议赋予create_dir_perms,基本涵盖对dir的所有权限,比如:{ open search write read rename create rmdir getattr }等等。
针对file缺少的任何权限,建议赋予rwx_file_perms,基本涵盖对file的所有权限,比如:包含{ open read write open execute getattr create ioctl }等等。
 

4、自定义规则**

给节点加权限,这类情况使用audit2allow工具一般就会给你一句:allow  xxx sysfs:file {read getattr open},然后贴到对应的te文件中,全编报错:neverallow xxxvim
因为sysf:file 相当于我们开放了所有文件的权限,这是不被允许的,所以我们只能对节点单独添加规则(如我给/sys/class/net/eth0/operate添加权限):
在设备内部执行ls -l /sys/class/net/eth0/ 发现他是个软链接(给软链接添加规则是无效的),

具体路径是/sys/devices/platform/soc/1c08000.qcom,pcie/pci0001:00/0001:00:00.0/0001:01:00.0/net/eth0/operstate

然后在file_contexts中加上新的scontext,如下(sysfs_eth是自定义的类型):
/sys/devices/platform/soc/1c08000.qcom,pcie/pci0001:00/0001:00:00.0/0001:01:00.0/net/eth0/operstate          u:object_r:sysfs_eth:s0

之后在file.te中加上:
# eth0 statustype sysfs_eth, fs_type, sysfs_type;

最后去system_app.te文件中添加规则:
allow system_app sysfs_eth:file { read getattr open };
allow system_app sysfs_eth:dir search;
 

常见编译问题:

1、ERROR 'duplicate declaration of type/attribute' at token ';' on line 14430
解决方法:type的重定义,把你自定义的type给改了;
2、neverallow
原生selinux不允许赋予该权限,如果项目无需过CTS,可以在system/sepolicy中去掉该项规则,如需过CTS,需找寻其他方式;
 
 
 
 
 
posted @ 2024-04-05 00:50  lethe1203  阅读(174)  评论(0编辑  收藏  举报