• SELinux for Android的基本知识和实战


    SELinux for Android的基本知识和实战

    1. 背景

    1. SELinux出现之前,Linux上的安全模型叫DAC。Linux DAC采用了一种非常简单的策略, 只是将资源和访问对象分类,根据访问者的分组和组对应权限决定来确定是否可以访问,但是这样就会出现只要取得root权限就可以为所欲为的情况。针对DAC的不足,所以在DAC之外设计了一个新的安全模型,叫MAC,MAC的做法就是任何进程想在SELinux系统中干任何事情,都必须先在安全策略配置文件中赋予权限。凡是没有出现在安全策略配置文件中的权限,进程就没有该权限。SELinux也属于MAC机制的一种,在selinux的约束下,即使你有root权限,如果无法通过MAC验证,那么一样的无法真正执行相关的操作。另外对每一项权限进行了更加完整的细化,可限制用户对资源的访问行为。
    2. Android是建立在标准的Linux Kernel基础上,Google为了进一步增强Android的安全性,经过多个版本的努力将SELinux引入了Android中,作为 Android 安全模型的一部分(SEAndroid),对所有进程强制执行强制访问控制 (MAC),甚至包括以 Root/超级用户权限运行的进程。借助 SELinux,Android 可以更好地保护和限制系统服务、控制对应用数据和系统日志的访问、降低恶意软件的影响,并保护用户免遭移动设备上的代码可能存在的缺陷的影响。SELinux 按照默认拒绝的原则运行:任何未经明确允许的行为都会被拒绝。SELinux 可按两种全局模式运行:
      • Permissive,宽容模式:权限拒绝事件会被记录下来,但不会被强制执行。
      • Enforce,强制模式:权限拒绝事件会被记录下来并强制执行。
      查看设备当前的SELinux方法
      adb shell getenforce
      
      • 1
      • 2
      临时切换SELinux模式:
      Permissive: adb shell setenforce 0
      Enforce: adb shell setenforce 1
      
      • 1
      • 2
      • 3

    在选择强制执行级别时只能二择其一,一般出厂的设备都要求强制模式,开发时在宽容模式解决完所有的权限问题后将会切换到强制模式。

    2. selinux的对象、域、类型等概念

    SELinux是一种基于域-类型(domain-type)模型的强制访问控制(MAC)安全系统,它有几个概念我们先了解下:

    • 对象(object):例如文件、进程、套接字、系统属性、IPC等系统资源

    • 类型(type):SELinux中所有的对象都会有对应的类型,这样才能根据类型实施不同的策略。举例, 默认情况下,应用的类型为 untrusted_app.

    • 域(daemain):对于进程而言,其类型也称为域

    • 属性(attribute):属性是多个具有共性的类型的集合

    • 上下文(context):也称为标签,SELinux给Linux的所有对象都分配一个安全上下文(Security Context), 描述成一个标准的字符串

      通过ps -Z和ls -Z命令看到的所有的进程和文件的安全上下文
      格式: user:role:type[:range]
      举例: u:r:untrusted_app:s0
      说明:
      1、u为user的意思。SEAndroid中只定义了一个SELinux用户,值为u。
      2、r为role的意思。role是角色之意,它是SELinux中一种比较高层次,更方便的权限管理思路,一个u可以属于多个role,不同的role具有不同的权限,SEAndroid也只定义了一个SELinux角色r。
      3、untrusted_app,代表该进程所属的类型untrusted_app, 进程的类型称为Domain
      4、S0和SELinux为了满足军用和教育行业,MLS将系统的进程和文件进行了分级,不同级别的资源需要对应级别的进程才能访问。

    • 策略(policy): SEAndroid安全机制主要是使用对象安全上下文中的类型来定义安全策略,策略是具体实施的规则,策略文件位于各级sepolicy目录下,后缀为".te"的文件

    2.1 安全上下文(Context)

    SELinux 上下文标签,为了支持平台和供应商 sepolicy 之间的区别,系统以不同的方式构建上下文文件以使它们分开, 使用这些上下文给系统对象分配标签。SEAndroid主要的上下文有以下几种

    • 文件上下文file_contexts:
      作用:用于为文件分配标签,并且可供多种用户空间组件使用

    • 属性上下文property_contexts
      作用:用于声明属性的安全上下文,以便控制哪些进程可以设置这些属性

    • 服务上下文service_contexts
      作用:用于为 Android Binder 服务分配标签,以便控制哪些进程可以为相应服务添加(注册)和查找(查询)Binder 引用,service_contexts对应使用servicemanager(binder)的服务上下文,hwservice_contexts对应使用hwservicemanager(hwBinder)的服务上下文

    • Seapp 上下文 seapp_contexts
      作用:用于为应用进程和 /data/data 目录分配标签。在每次应用启动时,zygote 进程都会读取此配置;在启动期间,installd 会读取此配置。

    • mac_permissions.xml
      作用:用于根据应用签名和应用软件包名称(后者可选)为应用分配 seinfo 标记

    值得注意的是vendor定制的目录下对应的上下文的名字一般都不会加前缀,和平台的对应文件保持一致,system的上下文和vendor的上下文会在init进程中一起加载。

    2.2 策略文件

    系统为我们预定于了很对规则,可分类为:

    1. 针对attribute的策略制定,例如:domain.te、file.te等
    2. 针对daemon domain的策略制定,例如:adbd.te、servicemanager.te、surfaceflinger.te等
    3. 针对系统的其他模块进行策略制定,例如:app.te、system.te、init.te等
    2.3 SEAndroid sepolicy的各个文件目录
    • system/sepolicy/public
      平台的公共策略,平台的sepolicy API,对vendor可见,vendor可以引用
    • system/sepolicy/private
      平台的专用策略,对vendor不可见
    • system/sepolicy/vendor
      供应商可以使用的政策和上下文文件(供应商可以根据情况忽略)
    • /device/manufacturer/device-name/sepolicy
      在设备对应的BoardConfig.mk 通过BOARD_SEPOLICY_DIRS添加的自定义供应商sepolicy路径
    • /vendor/manufacturer/device-name/sepolicy 同上

    3. 实战

    3.1 快速添加avc denied权限的万能公式

    这里主要是解决我们在开发中在日志获取到的avc denied的解决,因为selinux权限问题90%的场景都是在补足缺少的权限,这里有一个通用的方法帮我们解决此类问题,步骤如下:

    1. 首先获取avc的打印信息,可以通过logcat或者dmsg获取,一般logcat |grep avc就可以获取
      举例:

      type=1400 audit(0.0:1639): avc: denied { read } for name="u:object_r:hwservicemanager_prop:s0" dev="tmpfs" ino=2257 scontext=u:r:tcl_factory_service_default:s0 tcontext=u:object_r:hwservicemanager_prop:s0 tclass=file permissive=1
      
      • 1

      这里我们先介绍下对应的字段的概念:
      操作权限 - action 具体缺少的权限,这个权限属于tclass组
      源上下文 - scontext 发起者对象的类型
      目前上下文 - tcontext 正在操作的对象类型
      目标类 - tclass 正在操作的对象的类型

      说的简单一点就是:
      缺少什么权限: { read }权限,
      谁缺少权限: scontext=u:r:tcl_factory_service_default:s0
      对谁操作时缺少权限: tcontext=u:object_r:hwservicemanager_prop:s0
      什么类型的权限: tclass=file

      得出的权限解决语句:

      # tcl_factory_service_default.te
      allow tcl_factory_service_default hwservicemanager_prop:file { read };
      
      • 1
      • 2

      总结出的通用公式:

      要添加的权限语句: allow scontext tcontext:tclass { action };
      要添加的目标文件: {scontext}.te
      
      • 1
      • 2
    3.2 Audit2allow工具

    audit2allow是一个开源的工具,可帮助我们从avc日志中生成需要添加的权限语句。但是这个工具只是辅助,因为有时候它会给很泛的权限,虽然解决了问题,但是范围给的太大了,不安全。
    使用前记得source lunch下环境就可以在根目录下使用。可执行文件的位置:

    external/selinux/prebuilts/bin/audit2allow
    
    • 1
    1. 使用方法1,从dmsg中提取:
      (1) 提取所有的avc LOG.

      adb shell "cat /proc/kmsg | grep avc" > avc_log.txt
      
      • 1

      (2) 使用 audit2allow tool直接生成policy.

      audit2allow -i avc_log.txt  即可自动输出生成的policy
      
      • 1
    2. 使用方法2,从系统专门的文件中提取(google推荐)

      adb pull /sys/fs/selinux/policy
      adb logcat -b events -d | audit2allow -p policy
      
      • 1
      • 2
    3. 使用方法3,从logcat提取

      adb logcat -b all -d | audit2allow -p policy
      
      • 1
    3.4 为新的服务添加权限
    1. 例子1:为一个system分区的native服务添加权限(google的例子)

      1. 在对应的init.device.rc添加服务启动脚本
      service foo /system/bin/foo
      	class core
      
      • 1
      • 2
      1. 为服务创建一个新的域
        在对应的device sepolicy下创建foo.te, 例如:device/manufacturer/device-name/sepolicy/foo.te
      # foo service
      type foo, domain;
      type foo_exec, exec_type, file_type;
      
      init_daemon_domain(foo)
      
      • 1
      • 2
      • 3
      • 4
      • 5
      1. 给服务这个bin文件添加标签(上下文)
        在对应的device sepolicy下的file_contexts添加,例如:device/manufacturer/device- name/sepolicy/file_contexts
      /system/bin/foo   u:object_r:foo_exec:s0
      
      • 1
      1. 在device.mk中添加这个文件,或者拷贝对应的可执行文件(确保刷机起来后/system/bin/foo存在)

      2. 编译并烧录

      3. 根据avc denied提示,使用上面的通用公式添加缺少的权限

    2. 例子2: (HIDL|AIDL) HAL新服务添加selinux权限

    3. 例子3: JAVA 新服务添加selinux权限

    4. 例子4: 设备节点添加selinux服务

    3.5 neverallow的场景和绕开

    SELinux neverallow规则用于禁止在任何情况下都不应该发生的行为, 即会影响安全性的绝不允许的规则,删除neverallow节点将无法通过CTS认证。但是有时候我们的定制需求又需要解决某个权限被neverallow的情况,那么我们就得尝试如何绕开这个规则限制,只是争取绕开,没有什么万能的方法。

    1. 关于文件路径访问的neverallow绕开
    例子:logpersist访问data/p1路径
    
    由于我们要访问的目录path为/data/p1,将该目录定义成自己的Type,可以自定义Type,如下:
    
    在file.te中自定义一个type:
    type p1_data_file, file_type, data_file_type, core_data_file_type;
    
    在file_contexts中定义安全上下文:
    /data/p1(/.*)?            u:object_r:p1_data_file:s0
    
    在logpersist.te将allow语句改为:
    allow  logpersist  p1_data_file:dir write;
    
    然后在logpersist.te中单独将自定义的p1_data_file减去即可。
    neverallow logpersist {
      file_type
      userdebug_or_eng(`-misc_logd_file -coredump_file')
      with_native_coverage(`-method_trace_data_file')
      -p1_data_file
    }:file { create write append };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    1. 例子2:
      后续补充

    经常困扰的问题:

    1. Q: 有些SOC目录下分为private、public、vendor,里面文件都相同,我们到底应该改private、public、vendor哪个路径呢?
      A: 在device对应的BoardConfig.mk定义了不同版本所要编译包含的目录,以MK里配置的目录为准
    2. 如何快速验证策略是否通过编译,检查添加的权限是否合法,是否存在neverallow的现象
      A: make sepolicy -jxxx
  • 相关阅读:
    softmax,softmax loss和交叉熵的关系
    【培训课程专用】中断路由代码导读:当cpu运行在TEE来了一个Non secure Group1中断
    C++每日面经
    PIL(Python Imaging Library)图像处理库教程
    LearnOpenGL - Android OpenGL ES 3.0 基础特效实现
    一文带你了解【深度学习】中CNN、RNN、LSTM、DBN等神经网络(图文解释 包括各种激活函数)
    C++ 中的 lowbit
    【文献分享】将生态系统服务和景观连通性整合到生态安全格局优化中——以中国珠江三角洲为例
    85.(cesium之家)cesium模型在倾斜摄影上运动
    ubuntu给终端加代理服务器
  • 原文地址:https://blog.csdn.net/qq_40731414/article/details/126919088