声明
- 最近工作上涉及到对Android系统安全性的改造,在改造之前先分析整理下目前Android系统自身的安全性;
- 参考了一些文章及书籍,在这里大部分是对别人描述的提炼,我挑出一些对我有用的内容整理;
- 本文使用的代码是LineageOS的cm-14.1,对应Android 7.1.2,可以参考我的另一篇博客:
0 写在前面的
Android在Linux的基础上构建出了一个富框架(rich framework),但在它最核心的层面上,还要靠Linux来完成所有操作。它沿用了Linux提供的安全特性:权限(permission)、权能(capability)、SELinux和其它一些底层安全保护措施。
1 Android继承了Linux的安全模型
Linux的安全模型的基本规定如下:
-
每个用户都有一个数字形式表示的UID:具体的用户名是什么对系统来说无关紧要,因为用户名是给用户看的(这些用户名是专门分配给配置文件和它们所属的目录的所有者使用的)。注意:两个用户名可能会共享同一个UID,但出现这种情况,从系统的角度讲,实际上只是意味着一个UID有两套用户名/密码而己。
-
每个用户都有一个数字形式表示的主组(primary group) ID: 和用户名一样,用户组的名称也是无关紧要的。注意:有些GID也是系统保留的。
-
用户还可以加入其他的组: 传统上,用户加入其他组后,它是这些组中的成员的这一层关系是记录在/etc/group文件中的。在该文件中会列出:所有组的名称、GID和所有加入了某个组,但又不是把它作为“主组”的组成员。
-
文件的访问权限由特定用户(owner)、组(group)和“其他人员”(other)三部分组成:不论是文件还是目录,它们的访问权限都是以这种表达能力非常有限的模型表示的。由于这一模型的局限性,只能通过创建专门的用户组的方式来规定文件的访问权限。
maxingrong@soc02:~/LineageOS$ ls -aldrwxrwxr-x 37 maxingrong maxingrong 4096 Feb 14 14:47 .drwxr-xr-x 28 maxingrong maxingrong 4096 Jun 6 10:35 ..drwxrwxr-x 12 maxingrong maxingrong 4096 Feb 14 11:26 ctsdrwxrwxr-x 10 maxingrong maxingrong 4096 May 6 06:59 dalvikdrwxrwxr-x 15 maxingrong maxingrong 4096 Feb 14 11:29 hardwaredrwxrwxr-x 3 maxingrong maxingrong 4096 Feb 14 13:26 kerneldrwxrwxr-x 18 maxingrong maxingrong 4096 Feb 14 11:29 libcoredrwxrwxr-x 5 maxingrong maxingrong 4096 May 27 00:17 libnativehelperdrwxrwxr-x 12 maxingrong maxingrong 4096 Feb 14 11:29 lineage....
-
在Linux中,几乎所有的东西都是以文件的形式来访问的: 所以,系统资源的访问权限也是遵循文件访问权限约定的,表示相应设备的文件的访问权限的表示方式和普通文件是完全一样的,而且用户也可以像修改普通文件的访问权限一样,用chown/chgrp/chmod命令修改这些文件的访问权限。
-
UID 0是无所不能的,即root用户:由于检查文件访问权限的具体实现方式,UID 0实际上能够在任何情况下通过检查,root 用户在系统中拥有绝对的权力。
-
二进制可执行文件chomd能让程序以另一个用户的权限(或者加入另一个用户组)运行,也就是Linux中的set-user-ID和set-group-ID: 利用二进制可执行文件chmod修改的程序会被自动授予指定的权限。这一机制乍一看好像是个设计缺陷,但它实际上是个让普通用户能够临时切换执行特权操作[比如,切换某个用户的UID(su 命令)或者口令(password 命令)]的系统特性。注意:为了预防经过修改的二进制可执行文件被滥用,如果这些(己经被授权了的)二进制可执行文件被复制或移动到了别处,复制/移动过去的文件中的setuid 和setgid权限标志位会被清零(也就是不再拥有特权了)。
给文件加SUID和SUID的命令如下:chmod u+s filename 设置SUID位chmod u-s filename 去掉SUID设置chmod g+s filename 设置SGID位chmod g-s filename 去掉SGID设置
Android 也继承了这一经典模型只不过在用法上有一点区别: 在Android 中,“用户”这个概念是分配给各个应用,而不是分配给使用计算机的人的。突然之间,原本用来区分共享同一个UNIX 服务器的人类用户的方法,也被用在了应用身上,并且也用相同的隔离措施限定了它们可以使用的权限。一个“用户”不能访问另一个“用户”用户的文件,目录或是进程一一这种严密的隔离,使得可以同时并发地运行多个应用,并且使这些应用不会相互影响。
当一个应用初次安装时,PackageManager会把一个唯一的UID分配给它,这个ID也被称为“应用ID ”。这个ID的取值范围在10000~9000内,Android 的C运行时库bionic会自动把这个ID映射为app_XXX或u_XXX这种更方便人类阅读的格式。
1.1 系统定义的AID
Android系统保留了数字较小的UID (1000-9999),专供系统使用。这部分UID中只有一部分被使用了,相关定义写在源码目录:~/LineageOS/system/core/include/private/android_filesystem_config.h文件中:
/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *//* This file is used to define the properties of the filesystem** images generated by build tools (mkbootfs and mkyaffs2image) and** by the device side of adb.*/#ifndef _ANDROID_FILESYSTEM_CONFIG_H_#define _ANDROID_FILESYSTEM_CONFIG_H_#include#include #include #if defined(__ANDROID__)#include #else#include "android_filesystem_capability.h"#endif#define CAP_MASK_LONG(cap_name) (1ULL << (cap_name))/* This is the master Users and Groups config for the platform. * DO NOT EVER RENUMBER */#define AID_ROOT 0 /* traditional unix root user */#define AID_SYSTEM 1000 /* system server */#define AID_RADIO 1001 /* telephony subsystem, RIL */#define AID_BLUETOOTH 1002 /* bluetooth subsystem */#define AID_GRAPHICS 1003 /* graphics devices */#define AID_INPUT 1004 /* input devices */#define AID_AUDIO 1005 /* audio devices */#define AID_CAMERA 1006 /* camera devices */#define AID_LOG 1007 /* log devices */#define AID_COMPASS 1008 /* compass device */#define AID_MOUNT 1009 /* mountd socket */#define AID_WIFI 1010 /* wifi subsystem */#define AID_ADB 1011 /* android debug bridge (adbd) */#define AID_INSTALL 1012 /* group for installing packages */#define AID_MEDIA 1013 /* mediaserver process */#define AID_DHCP 1014 /* dhcp client */#define AID_SDCARD_RW 1015 /* external storage write access */#define AID_VPN 1016 /* vpn system */#define AID_KEYSTORE 1017 /* keystore subsystem */#define AID_USB 1018 /* USB devices */#define AID_DRM 1019 /* DRM server */#define AID_MDNSR 1020 /* MulticastDNSResponder (service discovery) */#define AID_GPS 1021 /* GPS daemon */#define AID_UNUSED1 1022 /* deprecated, DO NOT USE */#define AID_MEDIA_RW 1023 /* internal media storage write access */#define AID_MTP 1024 /* MTP USB driver access */#define AID_UNUSED2 1025 /* deprecated, DO NOT USE */#define AID_DRMRPC 1026 /* group for drm rpc */#define AID_NFC 1027 /* nfc subsystem */#define AID_SDCARD_R 1028 /* external storage read access */#define AID_CLAT 1029 /* clat part of nat464 */#define AID_LOOP_RADIO 1030 /* loop radio devices */#define AID_MEDIA_DRM 1031 /* MediaDrm plugins */#define AID_PACKAGE_INFO 1032 /* access to installed package details */#define AID_SDCARD_PICS 1033 /* external storage photos access */#define AID_SDCARD_AV 1034 /* external storage audio/video access */#define AID_SDCARD_ALL 1035 /* access all users external storage */#define AID_LOGD 1036 /* log daemon */#define AID_SHARED_RELRO 1037 /* creator of shared GNU RELRO files */#define AID_DBUS 1038 /* dbus-daemon IPC broker process */#define AID_TLSDATE 1039 /* tlsdate unprivileged user */#define AID_MEDIA_EX 1040 /* mediaextractor process */#define AID_AUDIOSERVER 1041 /* audioserver process */#define AID_METRICS_COLL 1042 /* metrics_collector process */#define AID_METRICSD 1043 /* metricsd process */#define AID_WEBSERV 1044 /* webservd process */#define AID_DEBUGGERD 1045 /* debuggerd unprivileged user */#define AID_MEDIA_CODEC 1046 /* mediacodec process */#define AID_CAMERASERVER 1047 /* cameraserver process */#define AID_FIREWALL 1048 /* firewalld process */#define AID_TRUNKS 1049 /* trunksd process (TPM daemon) */#define AID_NVRAM 1050 /* Access-controlled NVRAM */#define AID_DNS 1051 /* DNS resolution daemon (system: netd) */#define AID_DNS_TETHER 1052 /* DNS resolution daemon (tether: dnsmasq) *//* Changes to this file must be made in AOSP, *not* in internal branches. */#define AID_SHELL 2000 /* adb and debug shell user */#define AID_CACHE 2001 /* cache access */#define AID_DIAG 2002 /* access to diagnostic resources *//* The range 2900-2999 is reserved for OEM, and must never be * used here */#define AID_OEM_RESERVED_START 2900#define AID_QCOM_DIAG 2950 /* access to QTI diagnostic resources */#define AID_RFS 2951 /* Remote Filesystem for peripheral processors */#define AID_RFS_SHARED 2952 /* Shared files for Remote Filesystem for peripheral processors */#define AID_OEM_RESERVED_END 2999/* The 3000 series are intended for use as supplemental group id's only. * They indicate special Android capabilities that the kernel is aware of. */#define AID_NET_BT_ADMIN 3001 /* bluetooth: create any socket */#define AID_NET_BT 3002 /* bluetooth: create sco, rfcomm or l2cap sockets */#define AID_INET 3003 /* can create AF_INET and AF_INET6 sockets */#define AID_NET_RAW 3004 /* can create raw INET sockets */#define AID_NET_ADMIN 3005 /* can configure interfaces and routing tables. */#define AID_NET_BW_STATS 3006 /* read bandwidth statistics */#define AID_NET_BW_ACCT 3007 /* change bandwidth statistics accounting */#define AID_NET_BT_STACK 3008 /* bluetooth: access config files */#define AID_READPROC 3009 /* Allow /proc read access */#define AID_WAKELOCK 3010 /* Allow system wakelock read/write access */#define AID_RFS_OLD 3012 /* DEPRECATED OLD ID FOR RFS, DO NOT USE */#define AID_RFS_SHARED_OLD 3013 /* DEPRECATED OLD ID FOR RFS-SHARED *//* The range 5000-5999 is also reserved for OEM, and must never be used here. */#define AID_OEM_RESERVED_2_START 5000#define AID_OEM_RESERVED_2_END 5999#define AID_SENSORS 3011 /* access to /dev/socket/sensor_ctl_socket & QCCI/QCSI */#define AID_EVERYBODY 9997 /* shared between all apps in the same profile */#define AID_MISC 9998 /* access to misc storage */#define AID_NOBODY 9999#define AID_APP 10000 /* first app user */#define AID_ISOLATED_START 99000 /* start of uids for fully isolated sandboxed processes */#define AID_ISOLATED_END 99999 /* end of uids for fully isolated sandboxed processes */#define AID_USER 100000 /* offset for uid ranges for each user */#define AID_SHARED_GID_START 50000 /* start of gids for apps in each user to share */#define AID_SHARED_GID_END 59999 /* start of gids for apps in each user to share */#if !defined(EXCLUDE_FS_CONFIG_STRUCTURES)/* * Used in: * bionic/libc/bionic/stubs.cpp * external/libselinux/src/android.c * system/core/logd/LogStatistics.cpp * system/core/init/ueventd.cpp * system/core/init/util.cpp */struct android_id_info { const char *name; unsigned aid;};static const struct android_id_info android_ids[] = { { "root", AID_ROOT, }, { "system", AID_SYSTEM, }, { "radio", AID_RADIO, }, { "bluetooth", AID_BLUETOOTH, }, { "graphics", AID_GRAPHICS, }, { "input", AID_INPUT, }, { "audio", AID_AUDIO, }, { "camera", AID_CAMERA, }, { "log", AID_LOG, }, { "compass", AID_COMPASS, }, { "mount", AID_MOUNT, }, { "wifi", AID_WIFI, }, { "adb", AID_ADB, }, { "install", AID_INSTALL, }, { "media", AID_MEDIA, }, { "dhcp", AID_DHCP, }, { "sdcard_rw", AID_SDCARD_RW, }, { "vpn", AID_VPN, }, { "keystore", AID_KEYSTORE, }, { "usb", AID_USB, }, { "drm", AID_DRM, }, { "mdnsr", AID_MDNSR, }, { "gps", AID_GPS, }, // AID_UNUSED1 { "media_rw", AID_MEDIA_RW, }, { "mtp", AID_MTP, }, // AID_UNUSED2 { "drmrpc", AID_DRMRPC, }, { "nfc", AID_NFC, }, { "sdcard_r", AID_SDCARD_R, }, { "clat", AID_CLAT, }, { "loop_radio", AID_LOOP_RADIO, }, { "mediadrm", AID_MEDIA_DRM, }, { "package_info", AID_PACKAGE_INFO, }, { "sdcard_pics", AID_SDCARD_PICS, }, { "sdcard_av", AID_SDCARD_AV, }, { "sdcard_all", AID_SDCARD_ALL, }, { "logd", AID_LOGD, }, { "shared_relro", AID_SHARED_RELRO, }, { "dbus", AID_DBUS, }, { "tlsdate", AID_TLSDATE, }, { "mediaex", AID_MEDIA_EX, }, { "audioserver", AID_AUDIOSERVER, }, { "metrics_coll", AID_METRICS_COLL }, { "metricsd", AID_METRICSD }, { "webserv", AID_WEBSERV }, { "debuggerd", AID_DEBUGGERD, }, { "mediacodec", AID_MEDIA_CODEC, }, { "cameraserver", AID_CAMERASERVER, }, { "firewall", AID_FIREWALL, }, { "trunks", AID_TRUNKS, }, { "nvram", AID_NVRAM, }, { "dns", AID_DNS, }, { "dns_tether", AID_DNS_TETHER, }, { "shell", AID_SHELL, }, { "cache", AID_CACHE, }, { "diag", AID_DIAG, }, { "qcom_diag", AID_QCOM_DIAG, }, { "rfs", AID_RFS, }, { "rfs_shared", AID_RFS_SHARED, }, { "net_bt_admin", AID_NET_BT_ADMIN, }, { "net_bt", AID_NET_BT, }, { "inet", AID_INET, }, { "net_raw", AID_NET_RAW, }, { "net_admin", AID_NET_ADMIN, }, { "net_bw_stats", AID_NET_BW_STATS, }, { "net_bw_acct", AID_NET_BW_ACCT, }, { "net_bt_stack", AID_NET_BT_STACK, }, { "readproc", AID_READPROC, }, { "wakelock", AID_WAKELOCK, }, { "sensors", AID_SENSORS, }, { "rfs_old", AID_RFS_OLD, }, { "rfs_shared_old", AID_RFS_SHARED_OLD, }, { "everybody", AID_EVERYBODY, }, { "misc", AID_MISC, }, { "nobody", AID_NOBODY, },};#define android_id_count \ (sizeof(android_ids) / sizeof(android_ids[0]))struct fs_path_config { unsigned mode; unsigned uid; unsigned gid; uint64_t capabilities; const char *prefix;};/* Rules for directories and files has moved to system/code/libcutils/fs_config.c */__BEGIN_DECLS/* * Used in: * build/tools/fs_config/fs_config.c * build/tools/fs_get_stats/fs_get_stats.c * system/extras/ext4_utils/make_ext4fs_main.c * external/squashfs-tools/squashfs-tools/android.c * system/core/cpio/mkbootfs.c * system/core/adb/file_sync_service.cpp * system/extras/ext4_utils/canned_fs_config.c */void fs_config(const char *path, int dir, const char *target_out_path, unsigned *uid, unsigned *gid, unsigned *mode, uint64_t *capabilities);ssize_t fs_config_generate(char *buffer, size_t length, const struct fs_path_config *pc);__END_DECLS#endif#endif
下表中给出部分UID的宏定义以及它们在Android中的作用,这些UID大多也同时被用作GID:通过加入这些次级组,system_server、adb、installd及其他一些系统进程就能获得这些组对应的系统文件或设备的访问权限,这样是相当简单有效的策略。
Android的系统属性也依赖于UID进行访问控制一一init的property_service socket 是通过各种系统属性的命名空间(namespace)来进行访问限制的。同样的方法也被用来保证servicemanager(进程间通)赖以实现的关键服务)的安全性。尽管Binder最终是通过uid/pid模型提供安全保障的,但servicemanager也能够把众所周知的服务的名称的查询限制在指定uid范围内一一尽管uid O 或SYSTEM 用户总是例外的。
1.2 执行严格网络权限控制时使用的Android GID
当CONFIG_PARANOID_ANDROID被置为l时,Android 内核还能认出在3000到3999这个区间里的GID。这时,通过在内核中的套接字处理代码中强制添加GID检查的方式,使得与网络访问相关的所有功能都只能被这些GID或其组成员使用。注意,netd可以撤销这些设置,因为它是以root身份运行的。下表中是己知的与网络相关的AID。
1.3 服务分离
从Android 4开始,Android引入了“服务分离”(isolated service)这一概念。它使应用能把它的服务分离到一个完全隔离的区域(即在另一个拥有独立UID的进程里)运行。被分离出来的服务使用的是99000到99999(AID_ISOLATED_START从AID_ISOLATED_END)这个区间里的UID,servicemanager会拒绝所有来自这些进程的请求,其结果就是:这些进程不能使用任何系统服务,只能完成一些处理内存中数据的操作。这些服务主要是在Web浏览器之类的应用中使用,比如:Chrome。
1.4 拥有者为root 用户的进程
就像在Linux系统中一样,root用户(UID为0的用户)是无所不能的,但Android一直都在限制具有root权限的可执行文件的存在,为的是贯彻最小权限原则。之前有一些Android系统的root工具就是利用了root所拥有的进程中的漏洞(特别是vold,这个进程常被用作这类跳板)来root手机/平板电脑的,所以Google希望通过减少root所拥有的进程的数目的方式,缩小Android系统的受攻击面。比如installd,这个进程以前是拥有root权限的,不过从Android4.4开始,它的root权限就被去掉了。
不过把全部root所拥有的进程的root权限都去掉好像也是不可能的: 至少init进程、Zygote进程必须具有root权限。你可以用下面这条命令来列出你的手机中所有root 所拥有的进程:
ps | grep "root" | grep -v "2"
其中,“ grep -v " 命令的作用是忽略掉所有PPID 为2 的内核线程。下表列出的是,在cm14-1 Android系统中默认以root权限运行的服务。
以上这些root权限的进程都是AOSP中所必须的,还有些具有root权限二进制可执行文件是有设备商内置进来的,它们在很大程度上扩大Android系统的受攻击面。毕竟AOSP的root权限可执行文件是开源的,可以根据代码分析它的安全性,但厂商塞进来的这些二进制可执行文件都是闭源的,而且为了实现某些功能,有些厂商还会牺牲安全性。
我们可以预见到,最终Android只会让那些必须拥有root权限的服务保有root权限,而其它的服务都会像installd一样逐渐移除它的root权限。为了实现这一点,Android就需要采用Linux另外一个安全特性——Linux能力。
2 Linux能力
如果一个set-user-ID的二进制可执行文件是可信的,那么至少在理论上这一模型还是能有效工作的。不过在实践中, SetUID 天生就有一些安全隐患: 如果一个set-user-ID的二进制可执行文件中被发现存在安全漏洞,攻击者就能借助它取得root权限。常见的漏洞利用方式包括: 利用符号链接、竞争条件(借助存在漏洞的程序覆盖系统的配置文件)和代码注入(导致存在漏洞的程序执行一个拥有root权限的shell)。
Linux能力提供了一个能解决这一问题的解决方案一一把root权限拆分成若干种各不相交的子权限,每种权限用bitmask中的一个bit位来表示。通过对这个bitmask中的各个标志位进行设置,可以让相关程序能够执行与指定权限对应的特权操作,同时又将该程序的权限限制在被授予的权限范围内,使之不能执行其他类型的特权操作。这使得Linux能力成了“最小权限原则”的一种实现方式。下图可以解释这一点:
把权限限制在一个子集中一一只赋予那些绝对必须的权限,同时保留其他的权限,极大地增强了安全性。即便给定的应用程序或用户最终是恶意的(或者因为代码注入而执行了不该执行的操作),危害的范围也会被限制在一定的范围之内。权能就像是一个沙箱,允许应用执行设计所需的操作一一同时又防止它为所欲为,危害系统安全。事实上,能力还有个很好的副作用:我们能在root 账号的使用者并不是完全值得信任时,使用能力限制root 用户本身的行为。
init进程仍然会以root权限启动大部分Android 服务,在刚开始启动时这些服务进程的能力标志位确实是全部为true 的(bitmask为 Oxffffffffffffffff)。但是在这些服务进程开始真正做些什么之前, 它们会把自己的能力降下来,只保留它们必须使用的那部分能力。installd就是这样一个坚持最小权限原则的很好的例子:它会确保把除了安装包(package)所必需的权限之外的所有权限都交出去,其所在源码目录:~/LineageOS/frameworks/native/cmds/installd/commands.cpp
static void drop_capabilities(uid_t uid) { if (setgid(uid) != 0) { ALOGE("setgid(%d) failed in installd during dexopt\n", uid); exit(64); } if (setuid(uid) != 0) { ALOGE("setuid(%d) failed in installd during dexopt\n", uid); exit(65); } // drop capabilities struct __user_cap_header_struct capheader; struct __user_cap_data_struct capdata[2]; memset(&capheader, 0, sizeof(capheader)); memset(&capdata, 0, sizeof(capdata)); capheader.version = _LINUX_CAPABILITY_VERSION_3; if (capset(&capheader, &capdata[0]) < 0) { ALOGE("capset failed: %s\n", strerror(errno)); exit(66); }}
使用能力最多的用户无疑就是system_server 了。因为尽管这个进程的所有者是system ,但在执行许多它的普通操作时,还是需要root权限的。下表列出了各种Linux的能力,以及使用这些能力的Android进程。
我可以进入手机文件系统中查看我的手机中system_server的进程状态(因为我此时手机运行的system_server进程的PID为820,所以查看其中的status文件,从中可以看出四个关于Linux能力的bitmask):
hammerhead:/proc/820 $ cat statusName: system_serverState: S (sleeping)Tgid: 820Pid: 820PPid: 214TracerPid: 0Uid: 1000 1000 1000 1000Gid: 1000 1000 1000 1000FDSize: 512Groups: 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1018 1021 1032 3001 3002 3003 3006 3007 3009 3010 #所属的组VmPeak: 1864196 kBVmSize: 1810292 kBVmLck: 0 kBVmPin: 0 kBVmHWM: 138948 kBVmRSS: 129900 kBVmData: 268800 kBVmStk: 8192 kBVmExe: 20 kBVmLib: 87020 kBVmPTE: 478 kBVmSwap: 0 kBThreads: 123SigQ: 2/12268SigPnd: 0000000000000000ShdPnd: 0000000000000000SigBlk: 0000000000001204SigIgn: 0000000000000000SigCgt: 2000000200008cf8CapInh: 0000000000000000 #可以被子进程继承的能力CapPrm: 0000001006897c20 #被授予该进程的能力CapEff: 0000001006897c20 #活跃有效的能力那些被投予该进程, 而且也是该进程明确需要的能力)CapBnd: fffffff000000000 #权能范围Cpus_allowed: fCpus_allowed_list: 0-3voluntary_ctxt_switches: 7797nonvoluntary_ctxt_switches: 2519
从Android4.4开始,Zygote会去调用prctl(PR_CAPSET_DROP)和prctl(PR_SET_NO_NEW_PRIVS),以确保不会有其他能力添加给它的子进程(也就是用户打开的各种应用)。可以预见,vold和netd将来也都会主动降低自己的权限,只获取部分必须的权能,而不是像现在这样拥有root权限。
关于Linux的能力可以参考一本书《Linux/UNIX系统编程手册(下册)-第39章 能力》
3 SElinux (Security Enhanced Linux:安全加固的Linux)
SELinux最初由NSA开发时,只是Linux的一个补丁集,后来被合并进了内核主线,以提供一个能够根据预先定义的策略规则,对相关操作进行审查限制的强制访问控制(MAC,Mandatory Access Control)框架。类似Linux能力一样,SELinux也实现了最小权限原则,只是粒度更细。通过严格地防止(进程的)操作超出预定义的操作边界,SELinux极大地增强了系统的安全态势。只要进程的行为良好,就不会有任何问题。但如果进程行为不端(在大多数情况下,这可能是因为进程本身就是恶意的,也可能是因为进程被注入了恶意代码而在正常进程中出现恶意操作),SELinux 就会阻断所有这些越界操作。
SELinux一直到Android 4.4才被引入。现在SELinux默认被设为:对一些Android 服务(特别是对installd 、netd 、void 和zygote)启用了强制(Enforcing)模式,而对所有其他进程仍使用宽容模式。一般而言,对每个域(domain)先使用宽容模式,以便在把它设为强制模式之前,对相关策略规则进行测试,一般在不知道怎么配te文件时会先这样,根据SElinux的审计提示进行配置te文件。
3.1 策略规则
SELinux所使用的基本方法是“打标签”(大多数MAC框架所使用的基本方法)。所谓“标签”(label)就是为资源[客体(object)]分配一个类型(type),或为进程[主体(subject )]分配一个安全域(security domain)。SELinux可以据此强制让只有在同一个域中(打了同样的标签)的进程才能访问对应的资源。根据策略规则,域也可以是有限的(confined),这时,除了被允许访问的资源之外,进程就不能访问任何其他资源了。
策略也可以允许在某些情况下,给一些己经打了标签的对象重新打新的标签[relabelto和relabelfrom,也被称为域切换(domain transition)],在一个可信进程(比如,Zygote) fork()出一个不可信的进程(实际上就是用户安装的应用)时,这一操作是绝对必要的。
一个SELinux标签实际上就是一个4元组,也就是一个user: role: type: level格式的字符串。被打了同样标签(也就是处于同一个域中)的所有进程相互之间是等价的。目前SEAndroid中只定义了type,标签应该总是u:r:domain:s 这种形式的。在Android 5中,SEAndroid策略为每个守护进程都定义了一个独立的域(即每个守护进程都会有它自己的权限和安全profile设置),而Android应用中的类也有对应的域, 下表中列出的就是这些域:
所有的xxx_app域都是继承自最基本的domainpp这个域的。这个域只允许执行一些最基本的行为,其中包括使用Binder、与Zygote通信、surfraceflinger等。在AOSP的extemal/sepolicy目录下,可以找到记录所有域的详细定义的各个.te(type enforcement)文件。这些文件中使用的是一种混合了关键宇(keyword)和宏(来自temacros)的语法,定义了所有在这个域中允许或不允许执行的操作。
extemal/sepolicy 目录中的这些文件形成了一个基线,所有设备中使用的SELinux策略规则设置都是继承自它的。Google不鼓励厂商修改exteernal/sepolicy目录中的这些文件,而是鼓励在它们的BoardConfig.mk文件中通过添加四个特定变量的方式,自定义相关的SELinux策略规则。在这四个变量中:
- BOARD_SEPOLICY_REPLACE、BOARD_SEPOLICY_UNION、BOARD_SEPOLICY_IGNORE分别是用来替代、添加和忽略策略规则中的指定.te文件的;
- BOARD_SEPOLICY_DIRS则是用来添加搜索路径,使应用能够访问存有应用自己的 .t e 文件的目录的。这样做能够减少因为文件中出现错误,而在无意间改动了SELinux策略规则,进而产生安全漏洞的风险。
移动设备上存放的SELinux策略规则是将上述文件编译整合之后得到的二进制数据文件/sepolicy文件。这一做法进一步提升了安全性, 因为根文件系统是由initramfs mount上来的,而initramfs则是有数字签名保护的(因而也就可以被认为是不可修改的)系统镜像的一部分。
3.2 SELinux如何为资源打标签、设置上下文
3.2.1 应用的上下文
3.2.2 文件上下文
3.2.3 属性上下文
4 真它值得注意的特性
Android中也启用了Linux中的其他一些特性,以增强安全性,特别是对于其他一些不安全的默认设置进行加固,包括:AT SECURE、地址空间布局随机化(ASLR)、内核加固、栈保护、数据执行保护、编译时防护、seccomp-bpf等。
这些太专业了,我也搞不懂,就不分析了。