selinux资料

基础知识

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

Policy

policy是整个SEAndroid安全机制的核心之一,除了有好的安全架构外还必须有好的安全策略以确保让访问主体只拥有最小权限,使程序既能顺利执行基本功能又能防止被恶意使用。

在SEAndroid中主要采用了两种强制访问方法:

  • TE
  • MLS

这两种方法都在policy中得以实现,以下内容会先对policy规则的执行对象安全上下文有一个详细的介绍,然后再分别对SEAndroid中的TE机制和MLS机制做详细介绍。

标记安全上下文

SEAndroid中的安全上下文

SEAndroid的安全上下文与SELinux基本一致(除了MLS检测在SEAndroid中被强制执行),共有4个部分组成分别为user、role、type、sensitivity,以u:object_r:system_data_file:s0为例:

user:安全上下文的第一列为user,在SEAndroid中的user只有一个就是u。

role:第二列表示role,在SEAndroid中的role有两个,分别为r和object_r。

type:第三列为type,SEAndroid中共定义了139种不同的type。

security level:第四列是专为MLS访问机制所添加的安全上下文的扩展部分,格式为sensitivity[:category list][- sensitivity[:category list]],例如s0 - s15:c0.c1023,其中s0之后的内容可以不需要,冒号后面的内容是category,sensitivity和category组合一起声明了当前的安全级别(security level),“-”号左右分别标识了安全级别的最低和最高,这一列的参数将在MLS约束检查时用到,“15”、“1023”表示了sensitivity和category的最大值,这一参数可在Android.mk中定义。

安全上下文中最重要的部分就是第三列的type了,对于进程type被称为domain,type是整个SEAndroid中最重要的一个参量,所有的policy都围绕这一参量展开,所以为系统中每个文件标记上合适的type就显得极为重要了。在SEAndroid中关于安全上下文配置的核心文件主要是file_contexts文件、seapp_contexts文件和ocontexts文件。

安全上下文标记的四种方式

  • 基于策略语句标记

在SEAndroid的策略语言type_transition规则可以指定新创建的文件或目录的标签(安全上下文),通常情况下新创建文件的标签和其父目录的标签一致,但是可以使用type_transition规则为其指定特定的标签,有关transition的内容将在之后更详细地说明。

  • 默认标记

默认的标记行为在有关的策略标记规则不存在时使用,以及那些根本就没有关联策略标记规则的客体类别使用,大部分客体类别的默认标记都继承了创建它的进程/或包括客体的容器的安全上下文。

  • 程序请求标记

对于某些客体类别,SELinux提供了许多API允许程序明确地请求标记,这对于新创建的和已经存在的客体实例都一样。对于那些存储在支持标记的文件系统上的与文件有关的客体,SEAndroid通过调用相应API既能在创建文件时设置安全上下文,也能对与文件有关的客体进行重新标记,只需要适当的relabelfrom 和relabelto许可就可以明确地改变一个客体的标记,这些许可由policy进行严密控制。

  • 初始SID标记

安全上下文在用户态通过字符串来描述,而在内核中使用context数据结构来表示它。给每个context数据结构都分配一个u32 sid,该sid保存在描述内核数据结构的安全上下文中。内核驱动使用sidtab哈希表来描述所有已经分配了sid的context数据结构,通过查询该哈希表即可得到一个安全上下文所对应的sid。
几乎所有sid的分配和注册都是在运行时完成的,但是在refpolicy中定义了27个“Initial SID”,用于在内核驱动初始化时、由init进程通过selinuxfs接口加载policy之前,描述相应内核设施的初始安全属性。
初始SID提供了一种特殊的默认标记行为,初始SID适用于两种环境:在系统初始化策略还没有载入前对一部分内核相关的客体进行标记,以及当客体的安全上下文无效或安全上下文丢失时使用。初始sid的内容被定义在了initial_sids文件中,在ocontexts文件中同时声明了初始sid相应的安全上下文。


为文件系统和文件系统中的文件标记安全上下文

在SEAndroid中存在两种文件系统,一种是常见的文件系统包括传统的、本地文件系统都是用来在磁盘上或可移动介质上存储数据(如ext3和XFS),和为了兼容其它操作系统的非本地文件系统(如iso9660和vfat),另一种是存在于内存中被称为伪文件系统,它是用于内核和用户空间之间的通讯(如proc和sysfs),通过selinux库中提供的API函数完成。
文件系统的初始安全上下文的标记是在文件系统挂载时完成,另外普通文件系统上的文件在文件创建时就标记好了安全上下文并和文件一起存储在磁盘上,而伪文件系统只在运行时才会为其中的文件标记安全上下文。

为文件系统标记安全上下文是对该文件系统的所有inode节点进行安全上下文的标记,这些标记是最原始的标记,之后如有新的文件被创建并赋予了相应的安全上下文标记则将会执行覆盖操作保留最新的安全上下文。


对于文件系统的标记SEAndroid依据各文件系统的不同属性拥有不同的机制:

  • 基于支持扩展属性的文件系统标记(即允许保存安全上下文这一扩展属性的文件系统)(fs_use_xattr)

这一类文件系统包括yaffs2、jffs2、ext2、ext3、ext4、xfs、btrfs,它们的一个共性是都支持在磁盘上永久保存安全上下文这一扩展属性信息。它们都用同一个安全上下文u:object_r:labeledfs:s0被统一标记,这些都在ocontexts文件中被声明,使用fs_use_xattr语法实现。

另外对于这些有唯一且永久的节点号的传统文件系统来说,SEAndroid会用一个永久的标记映射来决定文件系统内的节点的安全上下文和文件系统本身的安全上下文,这个永久的标记映射是由一个或多个配置文件组成,在SEAndroid中就是file_contexts文件和seapp_contexts文件,这两个文件会和policy二进制文件一起构成整个SEAndroid的安全策略体系。

file_contexts文件对相应目录的使用正则表达式进行匹配,被匹配到的目录或文件都将被标记上相应的安全上下文,这个过程发生在文件系统标记完成之后执行。


  • 基于任务的文件系统标记(fs_use_task)

使用基于任务的标记时,在SEAndroid中使用 fs_use_task 规则声明新的与文件有关的客体继承创建它们的进程的安全上下文。使用基于任务的标记的文件系统不支持程序请求的标记,这种类型的标记行为多用于对于不真实存储用户数据但支持某种类型的内核资源的伪文件系统上。在SEAndroid中sockfs,pipefs都是基于这一方式进行安全上下文的标记,具体被标记的安全上下文内容都在ocontexts文件中有详细声明。


  • 基于转换的文件系统标记(fs_use_trans) 基于转换的文件系统标记与基于任务的文件系统标记非常类似,都使用的是伪文件系统,不同的是基于转换的安全上下文标记是基于类型转换规则(type_transition)实现的。在这样的文件系统上创建的文件都需要有一套相关的type_transition规则来完成。如果没有找到相应的type_transition规则,文件就会使用文件系统的初始安全上下文,文件系统的初始安全上下文被定义在了ocontexts文件中, 在SEAndroid中有devpfs、tmpfs、devtmpfs、shm、mqueue这些伪文件系统使用这一机制进行安全上下文标记。


  • 一般方式标记安全上下文(genfscon)

genfscon语句用于运行时标记伪文件系统和不支持扩展属性的传统文件系统。在SEAndroid中文件系统rootfs、proc、selinuxfs、cgroup、sysfs、inotifyfs、vfat、debugfs、fuse,都是采用这一方式进行安全上下文的标记,在ocontexts文件中定义了这些文件系统相应的安全上下文内容。


TE(Type Enforcement)

TE强制访问方式是SEAndroid中的最主要的安全手段,所有关于TE的强制访问规则都被定义在了后缀为te的文件中,在te文件中基本能总结为完成如下操作:

  • 对type类型的定义和将type归到相应的attribute中
SEAndroid在te文件中定义了安全策略中最基本的参量type,同时将具有共性的type归在一起构成一个称为attribute的集合,policy的规则执行也能以attribute作为执行对象。

SEAndroid为所有type共定义了17个attribute:
dev_type:

这一attribute包含了所有关于设备的type。

domain:

这一attribute包含了如下所列的所有关于进程的type,通常策略中的访问主体也就是进程所在的domain都包含在了这一attribute中。
adbd
trusted_app
browser_app
untrusted_app
bluetoothd
dbusd
debuggerd
drmserver
gpsd
init
installd
kernel
keystore
mediaserver
netd
nfc
qemud
radio
rild
servicemanage
shell
surfaceflinger
su
system_app
system
ueventd
vold
wpa
zygote

fs_type:

这一attribute包含了所有与文件系统相关的type。如下所列,大多是虚拟文件系统。
device
labeledfs
pipefs
sockfs
rootfs
proc
selinuxfs
cgroup
sysfs
sysfs_writable
inotify
devpts
tmpfs
shm
mqueue
sdcard
debugfs

file_type:

这一attribute包含了所有存在于非伪文件系统的相关文件的type,数量过多不再列举。

exec_type:

这一attribute包含了所有关于domian接入点的type,多被用在domain transition中,如下所列。
bluetoothd_exec
dbusd_exec
debuggerd_exec
drmserver_exec
gpsd_exec
installd_exec
keystore_exec
mediaserver_exec
netd_exec
qemud_exec
rild_exec
servicemanager_exec
surfaceflinger_exec
vold_exec
wpa_exec
zygote_exec

data_file_type:

这一attribute包含了所有在/data目录下的文件type,如下所列。
system_data_file
anr_data_file
tombstone_data_file
apk_data_file
dalvikcache_data_file
shell_data_file
gps_data_file
bluetoothd_data_file
bluetooth_data_file
keystore_data_file
vpn_data_file
systemkeys_data_file
wifi_data_file
radio_data_file
nfc_data_file
app_data_file

sysfs_type:

这一attribute包含了在sysfs文件系统下的所有文件的type,在SEAndroid中只有sysfs_writable包含在这个attribute中。

node_type:

这一attribute包含了所有与nodes/hosts有关的type,在SEAndroid中只有node包含在这个attribute中。

netif_type:

这一attribute包含了所有与网络接口相关的type,在SEAndroid中只有netif包含在这个attribute中。

port_type:

这一attribute包含了所有与网络端口相关的type,在SEAndroid中只有port包含在这个attribute中。

mlstrustedsubject:

这一attribute包含了所有能越过MLS检查的主体domain。

mlstrustedobject:

这一attribute包含了所有能越过MLS检查的客体type。

unconfineddomain:

这一attribute包含了所有拥有无限权限的type。

appdomain:

这一attribute包含了所有与app相关的type,如下所列。
trusted_app
browser_app
untrusted_app
nfc
radio
shell
system_app

netdomain:

这一attribute包含了所有与需要访问网络的app相关的type,如下所列。
trusted_app
browser_app
gpsd
mediaserver
radio
rild
system

bluetoothdomain:

这一attribute包含了所有与需要访问bluetooth的app相关的type,如下所列。
trusted_app
radio
system

binderservicedomain:

这一attribute包含了所有与binder服务相关的type,如下所列。
mediaserver
surfaceflinger
system


  • 通过allow语句制定主体客体强制访问规则(白名单规则,不再规则中的都默认为非法操作)
  • 通过type_transition语句制定tpye类型转换规则
  • 通过dontaudit语句声明对一些被安全策略拒绝的访问不再进行审核。
审核是对于发生了访问违规或出现了被系统安全规则拒绝的行为进行日志记录的过程,审核可以帮助系统管理员发现bug和可能的入侵尝试。
默认情况下,SEAndroid会记录被拒绝的访问检查,但策略语言dontaudit允许我们取消这些默认的预料之中的拒绝审核消息。


SEAndroid为系统定义了33个te策略文件,这33个策略文件是:
adbd.te、file.te、su.te、app.te、gpsd.te、netd.te、system.te、bluetoothd.te、init.te、net.te、ueventd.te、bluetooth.te、installd.te、nfc.te、unconfined.te、cts.te、kernel.te、qemud.te、vold.te、dbusd.te、keystore.te、radio.te、wpa_supplicant.te、debuggerd.te、mediaserver.te、rild.te、zygote.te、device.te、servicemanager.te、domain.te、shell.te、drmserver.te、surfaceflinger.te。

对上述33个文件根据其策略规则针对的对象可分为三类:

  • 针对attribute的策略制定:

attribute是多个具有共性的type的集合,以下六个文件主要是直接针对attribute制定的策略,这种针对attribute制定的策略也就是同时对多个type制定策略一样。
unconfined.te

主要是为unconfineddomain属性制定策略,这些策略基本就是对各种访问客体拥有所有的权限。

domain.te

主要是为domain属性制定策略,为所有归在其中的访问主体制定一些公共的策略。

CTS.te

主要是为appdomain制定策略,这些策略一般是在对app进行CTS测试时用到。

bluetooth.te

主要是为bluetoothdomain制定策略。

net.te

主要是为netdomain制定策略,这些策略主要是关于对sockets、ports的访问以及与netd的通信。

file.te

这个文件主要定义了各文件系统的type,各文件的type,socket的type,以及制定了在不同文件系统中创建文件的规则。



  • 针对daemon domain的策略制定:

adbd.te、gpsd.te、netd.te、bluetoothd.te、zygote.te、ueventd.te、installd.te、vold.te、dbusd.te、keystore.te、debuggerd.te、mediaserver.te、rild.te、drmserver.te、surfaceflinger.te、qemud.te、servicemanager.te、su.te、shell.te、wpa_supplicant.te
这些文件都是为系统中的daemon进程进行策略的制定,它们都有着相应的daemon domain。

  • 针对系统其他模块的策略制定:

最后的7个文件分别对系统的其他模块进行策略制定。
app.te

在这一文件里将安装在系统上的第三方app分类为受信任的app和不受信任的app,分别用不同的type表示,
再分别为这两种app在访问网络,bluetooth,sdcard,数据,缓存,binder等等名感位置时设置相应权限。

system.te

这一文件主要针对的是系统app和system server进程。对系统app访问binder、system data files、dalvikcatch、keystone等进行权限控制,
对system server访问网络、bluetooth、netlink、app、binder、device、data files、socket、cache files等进行权限控制。

init.te

在这一文件中声明了init拥有无限权限。

nfc.te

在这一文件中制定了nfc domain对nfc设备和相关数据文件的访问权限。

kernel.te

在这一文件中声明了kernel拥有无限权限。

radio.te

在这一文件中制定了radio domain对init、rild和相关数据文件的访问权限。

device.te

在这一文件中定义了所有跟设备相关的type,并将这些type都归到了dev_type属性中。


接下来对SEAndroid中制定的各种繁多的策略做一个简单分类:

转换(transition)

  • domain transition

某个程序被执行时,其相应的进程会处在相应的domain中,但当程序根据需要又执行了另一个程序时,进程就需要根据type transition规则进行domain transition以获得必要的权限从而使新进程能顺利访问到相关文件。另一个transition的原因是原有的domain权限过大,为了不让新启动的进程也继承过大的权限,因此需要domain transition。 在SEAndroid中几乎全部daemon进程都需要从init进程中启动,这就需要从init domian转换到daemon domain这一操作。
需要从init domain转换到daemon domain的进程有bluetoothd、dbusd、debuggerd、drmserver、gpsd、installd、keystore、mediaserver、netd、qemud、rild、servicemanager、surfaceflinger、vold、wpa_supplicant、zygote。
除了从init domain转换到其他daemon domain外,还有从adbd domain转换到shell domain,从shell domain转换到su domain,以及从zygote domain转换到system和appdomain,这主要是因为Android中的大部分进程都是由zygote创建。

  • type transition

type_transition 规则被用在Domain Transition中 或者确定新创建对象的标签,以重载其默认的、从父目录(containing directory)所继承的标签。通常情况下新创建文件的标签和其父目录的标签一致,但是可以使用type_transition规则为其指定特定的标签。
例如在SEAndroid中gpsd domain在以gps_data_file为type的目录下创建socket文件时,这些文件的type将会依照在策略中设定的type_transition规则而转换为gps_sokcket。
system domain在以wifi_data_file为type的目录下创建socket文件时,文件的type将会依照type_transition规则转变为system_wpa_socket。


文件和目录

在许多主体访问客体的情况中都需要对相关文件进行操作,SEAndroid对于牵涉到blk_file,chr_file,fd,fifo_file,lnk_file,sock_file和一般的file都进行了相关的策略制定。
还制定了一些domain指定type的目录、一般文件和链接文件只有读的权限的策略,例如dbusd domain对system type和bluetoothd type的目录和文件只有读的权限,domain attribute对proc、sysfs、inotify、cgroup这些虚拟文件系统中的文件和目录也只有读的权限,另外还有mediaserver domain对sdcard type的目录和文件只有读的权限,shell domain对apk_data_file的目录和文件只有读的权限、system domain对mediaserver和appdomain的目录和文件只有读的权限。
也制定了主体domain对不同文件系统的相关操作权限,以及当某个domain需要创建tmpfs、shmem、ashmem文件时,根据主体domain定义一个独特的type并对新创建的文件进行标记的策略。在SEAndroid里这条策略被用在了init、system、ueventd中。

无限权限

在SEAndroid中共定义了三个拥有巨大权限的attribute分别是mlstrustedsubject、mlstrustedobject、unconfineddomain,被分类到mlstrustedsubject的type在充当主体domain是可以越过MLS检查,被分类到mlstrustedobject的type在充当客体时可以越过MLS检查,被分到unconfineddomain的type则拥有所有权限可对客体进行任意操作。
在SEAndroid中被分在mlstrustedsubject attribute中的type有adbd、debuggerd、drmserver、init、installd、kernel、mediaserver、netd、surfaceflinger、su、system、vold、zygote。
被分在mlstrustedobject attribute中的type有alarm_device、ashmem_device、binder_device、log_device、mtp_device、nv_device、powervr_device、ptmx_device、null_device、cgroup、sysfs、sysfs_writable、sysfs_writable、sysfs_writable、debugfs、apk_data_file、cache_file、dnsproxyd_socket。
被分在unconfineddomain的type有init、kernel、su。

设备

关于设备这里重点提一下bluetooth,在SEAndroid中只对三个type提供bluetooth访问权限分别是trusted_app、radio、system。

App

在SEAndroid中指定了trusted_app、browser_app、untrusted_app、nfc、radio、shell、system_app这些type对系统中的所有app拥有适当的访问权限,并能对ashmem objects使用独特的type进行标记。

网络

SEAndroid对trusted_app、browser_app、gpsd、mediaserver、mediaserver、rild、system这些type授予了访问网络的权限。
在SEAndroid中系统对各类socket都制定了相应的策略,这些socket包括appletalk_socket(转为apple公司产品通信而设)、dccp_socket、netlink_audit_socket、netlink_dnrt_socket、netlink_firewall_socket、netlink_ip6fw_socket、netlink_kobject_uevent_socket、netlink_nflog_socket、、etlink_route_socket、netlink_selinux_socket、netlink_socket、netlink_tcpdiag_socket、netlink_xfrm_socket、packet_socket、rawip_socket、tcp_socket、tun_socket、udp_socket、unix_dgram_socket、unix_stream_socket。
SEAndroid还指定了如下策略允许一个本地socket从指定的客户端domain通过指定的socket连接到指定的服务端domain,第一列是客户端domain,第二列是指定的socket,第三列是服务端domain。

adbd, vold, vold                     
adbd, property, init
untrusted_app, dnsproxyd, netd
bluetoothd, dbus, dbusd           
netdomain, dnsproxyd, netd
radio, property, init               
radio, rild, rild
rild, property, init
rild, qemud, qemud                     
surfaceflinger, property, init
system_app, keystore, keystore
system, property, init
system, qemud, qemud                  
system, installd, installd
system, netd, netd               
system, vold, vold                 
system, zygote, zygote
system, keystore, keystore
system, dbus, dbusd               
system, gps, gpsd
system, bluetooth, bluetoothd
vold, property, init


另外SEAndroid只允许system和wpa这两个domain可以让一个本地socket以system和wpa任何一方为客户端另一方为服务端并通过某个socket进行数据包的发送。 运行一个本地socket从客户端domain通过发送数据包到服务端domain。

IPC

SEAndroid只允许adbd、appdomain、drmserver、mediaserver、surfaceflinger、system这些type或attribute通过servicemanager使用binder IPC。
SEAndroid只允许指定的客户端domain对指定的服务端domain使用binder IPC,如以下所列,第一列是指定的客户端domain,第二列是指定的服务端domain。

adbd, surfaceflinger
trusted_app, appdomain
appdomain, binderservicedomain
appdomain, trusted_app
drmserver, system
mediaserver, binderservicedomain
mediaserver, appdomain
surfaceflinger, system
system_app, appdomain
system, binderservicedomain
system, appdomain


SEAndroid只允许指定的客户端domain传送由服务端创建的binder references,如以下所列,第一列是指定的客户端domain,第二列是指定的服务端domain。

trusted_app, appdomain
appdomain, binderservicedomain
appdomain, trusted_app 
system_app, appdomain
system, binderservicedomain
system, appdomain


MLS(Multi-Level Security)

什么是MLS,为何要引入MLS

MLS称为多级别安全是另一种强制访问控制方法,特别适合于政府机密数据的访问控制,早期对计算机安全的研究大多数都是以在操作系统内实现MLS访问控制为驱动的。所有MLS的使用都是建立在TE安全的基础之上。在SELinux中MLS是一个可选访问控制方式,而在SEAndroid中则是被作为安全访问方式的其中之一。


MLS中的相关参量

在SEAndroid中mls的相关参量就是安全上下文的第四列称为security level,在安全上下文第四列中可以有一个或者两个security level,第一个表示低安全级别,第二个表示高安全级别。

每个security level由两个字段组成:

  • sensitivity

sensitivity有着严格的分级,它反应了一个有序的数据灵敏度模型,如政府分类控制中的绝密,机密和无密级。

  • category

category是无序的,它反应的是数据划分的需要。


基本思路是对于要访问的数据你同时需要足够的sensivity和正确的category。


在SEAndroid中sensitivity只有一个级别即s0,category共有1024个,因此最低安全级别就是s0,最高安全级别就是s0:c0.c1023。

security level之间的三种运算关系:

  • dom

需要主体sensitiviety大于客体,同时客体的category是主体的一个子集。

  • domby

与dom完全相反

  • eq

主体客体的sensitivity和category分别相同。


高的security level对低的security level拥有dom,低的security level对高的security level关系为domby(与dom相反),同级的security关系是eq,这三种关系运算符是SEAndroid中特有的。


MLS对进程的约束

  • 限制进程的domain转换

对于从一个domain转换到另一个domain的操作要求两个domain的高级别security level和低级别security level同时相等才能许可转换,除非是待转换的domain属于对mls无限权限的type。

  • 限制进程读操作

只有当主体domain的低级别security level对客体domain的低级别security level具有dom关系时,或者主体domian是属于对mls无限权限的type,主体才能对客体具有读操作的许可。

这一读操作具体是指:

  1. 能获取进程优先权
  2. 能获取另一进程的session id
  3. 能获取到进程的group id
  4. 能获取到系统的capabilities
  5. 能获取文件的属性信息
  6. 能追踪父程序或子程序的执行
  7. 允许通过clone或fork进程实现状态信息共享

总结一下就是MLS限制了低级别进程向高级别进程进行读的操作,即不能上读。

  • 限制进程写操作

只有当主体domain的低级别security level对客体domain的低级别security level具有domby关系时,或者主体domain是属于对mls无限权限的type,主体才能对客体具有写操作的许可。

写操作具体是指:

  1. 能发送SIGKILL信号
  2. 能发送SIGSTOP信号
  3. 能发送一个非SIGKILL、SIGSTOP、SIGCHLD的信号
  4. 能设置进程优先级
  5. 能设置进程group id
  6. 能设置系统的capabilities
  7. 能改变进程hard limits
  8. 能追踪父程序或子程序的执行
  9. 允许通过clone或fork进程实现状态信息共享

总结一下就是MLS限制了高级别进程对低级别进程写的操作,即不能下写。

MLS对socket的约束

  • 进程对local socket的访问限制

只有当主体进程的domain的高级别security level和低级别security level分别与客体local socket的type的security level相同时即满足eq关系时,或者主体客体任何一个具有对mls无限权限的type时,主体进程才对local socket拥有了某些访问权限。

这些访问权限是指:

  1. 读操作
  2. 写操作
  3. 新建操作
  4. 能获取对象属性信息
  5. 能设置对象的属性信息
  6. 能对对象重新标记安全上下文
  7. 能进行bind操作
  8. 能发起一个连接请求
  9. 能监听连接事件
  10. 能接受一个连接请求
  11. 能获取到socket options
  12. 能关闭socket连接
  • 对socket的datagram发送的限制

只有当发送方的低级别security level与接受方的低级别security level满足domby关系时,或者主体客体任何一个具有对mls无限权限的type时,发送方才对接受方拥有了发送权限。

  • 对客户端socket和服务端socket建立连接的限制

只有当客户端的低级别security level与服务端的低级别security level满足eq关系时,或者主体客体任何一个具有对mls无限权限的type时,客户端就能获得连接服务端的权限。

MLS对文件和目录的约束

  • 对文件的创建和重新标记的限制

对文件操作时,要求客体的文件安全上下文只有一个security level即没有低级别和高级别security level或者说是这两个级别相同。 当主体domain的低级别security level对客体文件的低级别security level相同时,或者主体具有对mls有无限权限的type时,主体对客体文件拥有创建、和重新标记安全上下文的权限。

  • 对目录的读操作的限制

只有当主体的低级别security level对客体目录的低级别security level满足dom关系时,或者主体客体任何一个具有对mls无限权限的type时,主体能对目录拥有如下权限:

  1. 能读目录
  2. 能获得目录的属性信息
  3. 能获得某个正在被访问文件的所有上层目录访问权(search权限)

总结一下就是对目录的访问不能上读。

  • 对文件的读操作的限制

只有当主体的低级别security level对客体文件的低级别security level满足dom关系时,或者主体客体任何一个具有对mls无限权限的type时,主体能对文件拥有如下权限:

  1. 能读文件
  2. 能获得文件的属性信息
  3. 能执行该文件

总结一下就是对文件的访问不能上读。

  • 对目录的写操作的限制

只有当主体的低级别security level对客体目录的低级别security level满足domby关系时,或者主体客体任何一个具有对mls无限权限的type时,主体能对目录拥有如下权限:

  1. 能对目录写操作
  2. 能设置属性信息
  3. 能重命名目录
  4. 能添加一个文件到目录中
  5. 能从目录中删除一个文件
  6. 能改变父目录
  7. 能删除一个空目录

总结一下就是对目录访问不能下写。

  • 对文件的写操作的限制

只有当主体的低级别security level对客体文件的低级别security level满足domby关系时,或者主体客体任何一个具有对mls无限权限的type时,主体能对文件拥有如下权限:

  1. 能对文件进行写操作
  2. 能设置文件属性信息
  3. 能对文件内容作append操作
  4. 能对文件创建链接
  5. 能删除一个文件的链接
  6. 能对文件重命名

总结一下就是对文件访问不能下写。

MLS对IPC的约束

  • 对IPC创建和销毁的限制

要求客体的IPC对象只有一个security level。

只有当主体的低级别security level与客体的低级别security level满足eq关系时,或者主体具有对mls无限权限的type时,主体能对客体IPC拥有创建和销毁的权限。

  • 对IPC读操作的限制

只有当主体的低级别security level对客体IPC的低级别security level满足dom关系时,或者主体具有对mls无限权限的type时,主体能对客体IPC拥有如下权限:

  1. 获取文件属性信息
  2. 能对IPC文件执行读操作
  3. 能关联一个key
  4. 能执行由IPC操作要求的读操作

总结一下就是对IPC访问不能上读。

  • 对IPC写操作的限制

只有当主体的低级别security level对客体IPC的低级别security level满足domby关系时,或者主体具有对mls无限权限的type时,主体能对客体IPC拥有如下权限:

  1. 能对文件执行write和append操作
  2. 能执行由IPC操作要求的write和append操作

总结一下就是对IPC访问不能下写。





所支持的MAC服务

MAC和MMAC功能概述:

  • 标准的SELinux MAC 策略是基于type enforcement(TE,即类型强制访问)/ multi-level security (MLS,即多级别安全机制),也可以理解为是一种白名单机制;
  • Install MMAC策略中的package和signature标签支持通过setinfo标签,来指定应用的context(安全上下文,指运行时domain)。该策略只对预装应用生效,而第三方的应用则无法通过这种方式指定,所有的第三方应用都只能由<default>标签匹配,而且seinfo的值为“default”。(译者注,这里会让你看得头晕,建议找到mac_permissions.xml文件对着看)
    • SEAndroid Install MMAC策略还能能够检查应用所申请的权限列表是否被允许。如果不允许,那么该应用就不能够安装。另外如果这款应用已经安装在手机上了,后来策略更新并与其产生冲突了,那么这款应用也不能运行。配置文件允许的动作有:allow(允许),deny(拒绝)和allow all permissions(允许所有权限)。 检查流程如下:
      • 安装或升级第三方应用时,它的权限列表都被会检查。如果在<default>里存在任意一项不被允许的权限,那么该应用安装或升级过程就会失败;
      • 预装的应用,他们的升级过程,系统也会去做一次权限检查。如果在package或者signature标签存在不允许的权限,更升级失败。如果存在某个权限,在package或者signature标签中没有显式声明为allow,而在default标签中声明为deny的话,升级过程同样会失败;
  • Intent MMAC策略的作用是决定Intent是否能够被分发到其他几种组件。策略会屏蔽掉所有没有被定义为允许的Intent分发。这是一个可选的策略,并不需要定制的SELinux策略支持,不过它可以对“主体”的安全上下文进行合法性校验。
  • Content Provider MMAC策略作用是决定content provider的访问请求是否被允许。策略会屏蔽掉所有没有被定义为允许的访问请求。目前的版本支持use, read, read/write三种权限。这是一个可选的策略,并不需要定制的SELinux策略支持。
  • Revoke permissions策略的作用是决定权限在运行过程中是否会被检查,如果权限被撤消了那么权限就会变成denied状态(也就是说,除了指定的权限会被变成denied,其他的权限都是允许的)。这是一个可选的策略,并不需要定制的SELinux策略支持。


Android为支持MAC所引入的变化

SE for Android为Android的内核增加了SELinux的支持,同时在用户空间也实现了如下几方面的目标:

  1. 定义所有具有特权守护进程,以防止权限被滥用以及把它们的破坏降到最低;
  2. 构造沙箱,使应用与应用和系统之间互相隔离;
  3. 防止应用提权;
  4. 利用MMAC策略,使应用的权限在安装和运行的过程中变得可控;
  5. 提供一种集中的、可分析的策略;
这些目标是由下列改措实现的:
  • 实现了yaffs2文件系统的安全标注;
  • 文件系统镜像文件(yaffs2和ext4)编译时标注;
  • 为recovery console和程序更新器提供标注功能;
  • 基于内核的Binder IPC权限检测;
  • 实现对由init进程所产生的服务端套接字(service sockets)和本地套接字文件(socket files)的标注功能;
  • 实现对由ueventd进程所产生的设备节点(device nodes)的标注功能;
  • 为应用和应用数据文件夹提供灵活易配置的标注功能;
  • 最小化SELinux用户空间的可用端口;
  • 提供了JNI方式的SELinux接口;
  • 为Zygote socket commands的使用提供了用户空间级别的权限检查;
  • 为Android properties的使用提供了用户空间级别的权限检查;
  • 专门针对Android编写了TE策略文件;
  • 为所有系统服务和应用定义domain;
  • 利用MLS类别隔离应用;
SE 对Android项目的变动
  • external/libselinux
提供了SELinux用户空间的函数库并集成到设备上。该库在原版本的基本上为适应Android而增加了一列的函数,如下所示:
  • selinux_android_setcontext
利用这个函数可以为应用设置正确的domain上下文,它会利用保存在seapp_contexts文件里的信息计算出正确的上下文。如果是在初始化阶段,这个函数也会调用selinux_android_seapp_context_reload加载seapp_contexts文件并对里面的每一项进行排序,详细过程见"seapp_contexts文件"一节。
该函数会被dalvik/vm/native/dalvik-system-Zygote.cpp和system/core/run-as/run-as.c调用。
  • selinux_android_setfilecon2
利用这个函数可以为应用文件夹和文件设置正常的上下文,它会利用保存在seapp_contexts文件里的信息计算出正确的上下文。如果是在初始化阶段,这个函数也会调用selinux_android_seapp_context_reload加载seapp_contexts文件并对里面的每一项进行排序,详细过程见"seapp_contexts文件"一节。
当安装应用时,该函数会被frameworks/base/cmds/installd/commands.c调用。
  • selinux_android_restorecon
利用这个函数可以让文件的上下文恢复成file_contexts文件里初始配置。该函数在初始经和安装等过程过程中会被多处调用。
  • selinux_android_load_policy
如果SELinux是开启的话,利用该函数可以加载SELinux文件系统,并通过调用selinux_android_reload_policy把策略文件加载到内核。
  • selinux_android_reload_policy
加载策略文件进内核。该函数会被system/core/init.c调用。
  • external/libsepol
提供了用户空间的策略工具库。这部分代码跟SELinux是一样的,而且不会集成到设备上。
  • external/checkpolicy
提供了策略构造工具。这部分代码跟SELinux是一样的,而且也不会集成到设备上(因此策略的构造必须在主机开发环境中进行)。
  • external/sepolicy
这个SE for Android特有的部分,里面包含各种策略模块(*.te文件),class/permissoin文件等等。所有策略模块依据Android.mk文件进行构造的,最终会连同其他配置文件(file_contexts, seapp_contexts和property_contexts)一起集成到设备上(编译成sepolicy文件)。也有一些工具可以根据不同的设备进行策略补充,这部分会在“策略构建”一节详细描述。
策略文件的在“SELinux MAC配置文件”一节进行详细描述。相关的工具也会在“策略构建工具”一节有详细的描述。
这里也包含了关于SE for Android的类定义,详细可以查看“SE for Android 的类和权限”一节。
这个文件夹也包含了Install MMAC、Intent MMAC、Content Permission MMAC策略,如果有配置的话,请参考“ SE for Android 系列之整体概要(一)”中的“ SE for Android的项目编译”一节。
  • external/mac-policy
这里包含revoke permission的策略配置文件(revoke_permission.xml),利用这种策略可以让Android的权限动态撤消。 如果项目选项选择revoke_perms的话,就会包含这个文件夹。
  • build
针对SE for Android进行修改。
  • dalvik
当进程被fork后,会使用selinux_android_setcontext进行domain上下文设置。
  • libcore
Zygote.java里添加了setInfo和niceName两种传入参数(译者注,应该是zygote command命令里添加了--setInfo和--niceName两种配置)
  • frameworks/base
    • JNI——添加了SELlinux的函数支持,如isSELinuxEnabled和setFSCreateCon。
    • SELinux 的Java类和方法的定义。
    • Zygote连接者的安全上下文检查。
    • 为package manager和各种service提供文件权限的管理(译者注,这里不太明白)
    • 添加MMAC框架
  • system/core
    • 支持SELinux的toolbox,比如load_policy, runcon
    • 支持SELinux的系统初始化,比如init,init.rc
    • 支持SELinux的核审服务(audittd)
  • system/extras
支持SELinux的ext4文件系统
  • kernel
已经有多个内核增加了LSM和SELinux支持,详细可以查看SEforAndroid - Building for a Device.
Android的内核存在多个版本(目前是3.4,模拟器使用的是Goldfish),因此最新版本的SELinux一般还没有集成到SEforAndroid。在“内核LSM和SELinux的支持”一节里,会详细说明内核的变化。

  • device

关于支持设备的详情情况,可以查看SEforAndroid - Building for a Device

可以修改设备的配置文件定制策略文件,详细见“构建策略文件”一节



内核LSM和SELinux的支持

文章 Security Enhanced (SE) Android: Bringing Flexible MAC to Android对内核的修改情况做了很好的描述,下面主要讲一下为支持Binder IPC服务所作的变化:

  1. Linux安全模块(LSM)在binder驱动代码(drivers/staging/android/binder.c和include/linux/security.h)添加了钩子逻辑;
  2. 在没有其他模块的情况下,默认支持能力("capabilities")(security/capability.c);
  3. LSM安全模块添加了钩子逻辑;
  4. 对显示在“SE for Android的类别和权限”一节中所列的客体类别和权限提供支持(security/selinux/include/classmap.h);


SE for Android的客体类别和权限

SE for Android添加了三个客体类别(binder, zygote和property_service),下表描述它们权限:
binder 类别 - 这是管理内核Binder IPC服务的客体类别
权限 描述
call 通过IPC方式访问一个指定的进程(A能否访问B?)。
impersonate 接管IPC通讯(A能否接管B的IPC通讯?)。
目前策略还没有使用,但selinux_binder_transaction调用时内核有做检查。
set_context_mgr

把自身注册成Binder Context Manager。如果A能为把B设置为context manager,就意味着A==B。参考策略文件servicemanager.te

transfer 传递binder引用给其他进程 (A能否把binder引用传递给B?)。


zygote  类别 – 这是用户空间的客体类别,管理Android应用的装载。参考SELinux.checkSELinuxAccess. In ZygoteConnection.java
权限 描述
specifyids 指定应用的uid或者gid
specifyrlimits 指定应用的资源限制
specifycapabilities 指定应用的capabilities
specifyinvokewith 指定应用要使用--invoke-with启动Zygote,这是一种包装命令的使用方式
specifyseinfo 指定seinfo标签决定应用的安全上下文


property_service 类别 – 这是用户空间的类别,用于管理Android Property Service
权限 描述
set 设置一个属性



SELinux命令行
SE for Android为Android了一个SELinux命令的子集,见表1。他们作用于Toolbox命令,也可以通过adb shell命令调用,比如:
adb shell su to setenforce permissive

表1:开启SELinux的adb shell命令(在Android toolbox里)

命令 注释
chcon 修改文件的安全上下文. 只支持第一部分的chcon(1)功能 (目前仅支持context pathname的格式).
chcon context pathname
getenforce 获取当前的工作模式
getenforce
getsebool Get SELinux boolean value(s):
getsebool [-a | boolean]
id 不带任意选项,如果开启了SELinux,那么安全上下文的信息就会自动显示
load_policy 把新策略加载入内核
load_policy policy-file
ls 支持通过-Z选项显示安全上下文信息
restorecon 按file_contexts文件的策略恢复文件的安全上下文。与restorecon(8)相比,有部分选项不支持
restorecon [-nrRv] pathname
runcon 以指定的安全上下文件运行命令
runcon context program args...
setenforce 修改SELinux的工作模式
setenforce [enforcing|permissive|1|0]
setsebool 修改SELinux布尔值(需要注意,这种修改重启后失效)
setsebool name [1|true|on|0|false|off]



SELinux 的公开方法
这些公开方法等价于在liselinux里的方法,见表2。源码在framework/base/java/andoid/os/SElinux.java。

表2:SELinux公开的类和方法

boolean isSELinuxEnabled()
   获取SELinux开启状态 
   如果上开启状态,则返回true
boolean isSELinuxEnforced()
   判断SELinux是否处于permissive或enforcing模式
   如果是enforcing模式,则返回true
boolean setSELinuxEnforce(boolean value)
   设置SELinux的工作模式(permissive或者enforcing)
   value为true表示enforcing模式
   设置成功返回true
boolean setFSCreateContext(String context)
   设置新建文件对象的安全上下文
  context为被指定安全上下文
   设置成功返回true
boolean setFileContext(String path, String context)
   修改现有文件的安全上下文
  path是被修改的文件路径
  context为被指定的安全上下文
   设置成功返回true
String getFileContext(String path)
   获取文件的安全上下文
   path 文件路径.
   返回文件的安全上下文件字符串或者null
String getPeerContext(FileDescriptor fd)
   获取本地socket的安全上下文
   FileDescriptor是socket所绑定的文件
   返回socket上下文件字符串或者null
String getContext()
  获取当前进程的安全上下文
   返回当前进程的安全上下文或者null
String getPidContext(int pid)
   获取指定pid的进程安全上下文
   pid 进程pid
   返回进程的安全上下文或者null
String[] getBooleanNames()
   获取SELinux的布尔值键名列表
   返回包含所有SELinux布尔值键名的字符串数组
boolean getBooleanValue(String name)
   获取指定键名的布尔值
   name 键名.
   返回true或false
boolean setBooleanValue(String name, boolean value)
   根据键名设置布尔值。需要注意,重启后会失效。
   name 键名
   value 重的布尔值
   操作成功返回true
boolean checkSELinuxAccess(String scon, String tcon, String tclass, String perm)
   判断两个安全上下文之间指定的权限是否被允许
   scon 源或宾体安全上下文
   tcon 目标或客体安全上下文
   tclass 客体类别名称
   perm 权限名称
   权限允许则返回true
boolean restorecon(String pathname)
   恢复文件为默认的安全上下文。如果系统没有包含SElinux或者处于关闭状态,都会自动返回true
   pathname 文件路径
   操作成功则返回true
   如果pathname为null会抛NullPointerException异常
boolean restorecon(File file)
   恢复文件为默认的安全上下文。如果系统没有包含SElinux或者处于关闭状态,都会自动返回true
   file 文件对象. 
   操作成功则返回true
   如果file为null会抛NullPointerException异常



Android init语言对SELinux的扩展
Android的init进程语言已经被扩展成为能够支持SELinux,见表3。完整的Android init语言描述见system/core/init/readme.txt文件

表3:SELinux init 扩展
seclabel <securitycontext>

在服务在运行之前修改其安全上下文,主要用在位于rootfs分区的服务,比如ueventd, adbd。而位于system分区的服务,则可以通过transitions规则进行修改,如果没有指定transition规则,那么默认就是init context

restorecon <path>

根据file_contexts的配置恢复指定路径的文件安全上下文. 

setcon <securitycontext>

设置当前进程的安全上下文。这一般用在early-init里设置init进程的安全上下文用的(见下面使用示例)。

setenforce 0|1

设置SELinux工作模式. 0 代表 permissive , 1 代表 enforcing。

setsebool <name> <value>

设置SELinux的布尔值

<value> 可以是 1|true|on 或者 0|false|off

使用示例见下面init文件的片断:

# system/core/rootdir/init.rc

...
on early-init
    # Set init and its forked children's oom_adj.
write /proc/1/oom_adj -16

    # Set the security context for the init process.
    # This should occur before anything else (e.g. ueventd) is started.
setcon u:r:init:s0
start ueventd
...
on boot
...
service ueventd /sbin/ueventd
    class core
    critical
    seclabel u:r:ueventd:s0
# device/generic/goldfish/init.goldfish.rc

...
on boot
    setsebool in_qemu 1
    restorecon /sys/qemu_trace/process_name
    restorecon /sys/qemu_trace/state
    restorecon /sys/qemu_trace/symbol
...


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值