浅入浅出 Android 安全:第一章 Android

by admin on 2020年3月1日

近日,谷歌开源了
Sandboxed API(沙箱式
API)。该项目用于在 Linux
系统上运行的 C/C++
库,是谷歌公司内部多年来一直在数据中心使用的工具,可以帮助开发人员免受恶意用户的输入和漏洞利用。

1.1 Android 技术栈

Android 是一个用于各种移动设备的软件栈,以及由 Google
领导的相应开源项目[9]。 Android 由四个层组成:Linux
内核,本地用户空间,应用程序框架和应用程序层。
有时本地用户空间和应用程序框架层被合并到一个层中,称为 Android
中间件层。 图 1.1 表示 Android 软件栈的层级。
粗略地说,在这个图中,绿色块对应在 C/C++ 中开发的组件,而蓝色对应在 Java
中实现的组件。 Google 在 Apache 2.0 许可证下分发了大部分 Android 代码。
此规则最值得注意的例外是 Linux 内核中的更改,这些更改在 GNU GPL V2
许可证下。

澳门新葡亰网址下载 1

Linux 内核层。在 2005 年被 Google 认识之前,Android 是 Android Inc.
公司的初创产品。创业公司的特点之一是,他们倾向于最大限度地重复利用已经存在的组件,以减少其产品的时间和成本。
Android 公司选择 Linux 内核作为他们新平台的核心。在 Android 中,Linux
内核负责进程,内存,通信,文件系统管理等。虽然 Android
主要依赖于“vanilla” Linux
内核功能,但是已经做出了系统操作所需的几个自定义更改。其中
Binder(一个驱动程序,提供对 Android 中的自定义 RPC / IPC
机制的支持),Ashmem(替代标准的 Linux
共享内存功能),Wakelocks(一种防止系统进入睡眠的机制)是最值得注意的更改[19]。虽然这些变化被证明在移动操作系统中非常有用,但它们仍然在
Linux 内核的主要分支之外。

本地用户空间层。通过本地用户空间,我们可了解在 Dalvik
虚拟机之外运行的所有用户空间组件,并且不属于 Linux Kernel
层。这个层的第一个组件是硬件抽象层(HAL),它与 Linux
内核和本地用户空间层之间实际上是模糊的。在 Linux
中,硬件驱动程序嵌入到内核中或作为模块动态加载。虽然 Android 是建立在
Linux
内核之上,它利用了一种非常不同的方法来支持新的硬件。相反,对于每种类型的硬件,Android
定义了一个
API,它由上层使用并用于与这种类型的硬件交互。硬件供应商必须提供一个软件模块,负责实现在
Android 中为这种特定类型的硬件定义的API。因此,此解决方案不再允许
Android
将所有可能的驱动程序嵌入内核,并禁用动态模块加载内核机制。提供此功能的组件在
Android
中称为硬件抽象层。此外,这样的架构解决方案允许硬件供应商选择许可证,在其下分发它们的驱动程序[18,19]。

内核通过启动一个名为 init 的用户空间进程来完成其启动。 此过程负责启动
Android 中的所有其他进程和服务,以及在操作系统中执行一些操作。
例如,如果关键服务在 Android 中停止应答,init 进程可以重新启动它。
该进程根据init.rc配置文件执行操作。 工具箱包括基本的二进制文件,在
Android [19]中提供shell工具的功能。

Android 还依赖于一些关键的守护进程。
它在系统启动时启动,并在系统工作时保持它们运行。
例如,rild(无线接口层守护进程,负责基带处理器和其他系统之间的通信),servicemanager(一个守护进程,它包含在
Android 中运行的所有 Binder 服务的索引),adbd(Android Debug Bridge
守护进程,作为主机和目标设备之间的连接管理器)等。

本地用户空间中最后一个组件是本地库。
有两种类型的本地库:来自外部项目的本地库,以及在 Android
自身中开发的本地库。 这些库被动态加载并为 Android
进程提供各种功能[19]。

应用程序框架层。 Dalvik 是 Android
的基于寄存器的虚拟机。它允许操作系统执行使用 Java 语言编写的 Android
应用程序。在构建过程中,Java 类被编译成由 Dalvik VM 解释的.dex文件。
Dalvik VM 特别设计为在受限环境中运行。此外,Dalvik VM
提供了与系统其余部分交互的功能,包括本地二进制和库。为了加速进程初始化过程,Android
利用了一个名为 Zygote
的特定组件。这是一个将所有核心库链接起来的特殊“预热”过程。当新应用程序即将运行时,Android
会从 Zygote
分配一个新进程,并根据已启动的应用程序的规范设置该进程的参数。该解决方案允许操作系统不将链接库复制到新进程中,从而加快应用程序启动操作。在
Android 中使用的 Java 核心库,是从 Apache Harmony 项目借用的。

系统服务是 Android 的最重要的部分之一。 Android
提供了许多系统服务,它们提供了基本的移动操作系统功能,供 Android
应用开发人员在其应用中使用。
例如,PackageManagerService负责管理(安装,更新,删除等)操作系统中的
Android 包。 使用 JNI
接口系统服务可以与本地用户空间层的守护进程,工具箱二进制文件和本地库进行交互。
公共 API 到系统服务都是通过 Android 框架库提供的。
应用程序开发人员使用此 API 与系统服务进行交互。

Android 应用程序层。 Android 应用程序是在 Android
上运行的软件应用程序,并为用户提供大多数功能。 Stock Android
操作系统附带了一些称为系统应用程序的内置应用程序。 这些是作为 AOSP
构建过程的一部分编译的应用程序。
此外,用户可以从许多应用市场安装用户应用,来扩展基本功能并向操作系统引入新的功能。

转载请注明出处:

未来计划

Sandboxed API 和 Sandbox2
已经被谷歌的许多团队使用。虽然该项目已经成熟,但除了维护之外,谷歌也做了一些未来的计划:

  • 支持更多的操作系统:目前只支持 Linux。开发团队将研究如何将 Sandboxed
    API 引入类 Unix 系统,如 BSD(FreeBSD,OpenBSD) 和 macOS。Windows
    端是一项更难的任务,还需要更多的基础工作才能实现。

  • 新的沙盒技术:随着硬件虚拟化技术的流行,用沙盒将代码限制在虚拟机中有了实现的可能性。

  • 系统构建:目前是使用 Bazel
    构建项目,这其中包括依赖项。但这不是每个人都想要的使用方式,因此
    CMake 支持有着很高的任务优先级。

  • Sandboxed API 的传播:使用 Sandboxed API
    来保护开源项目,有机会参与补丁奖励计划。

(文/开源中国)    

1.2 Android 一般安全说明

Android
的核心安全原则是,对手应用程序不应该损害操作系统资源,用户和其他应用程序。
为了促使这个原则的执行,Android
是一个分层操作系统,利用了所有级别提供的安全机制。 专注于安全性,Android
结合了两个层级的组件[?,?]:Linux 内核层和应用程序框架层(参见图
1.2)。

在 Linux 内核层级,每个应用程序都在特殊的应用程序沙箱中运行。
内核通过使用标准 Linux
设施(进程分离,以及通过网络套接字和文件系统的任意访问控制)来强制隔离应用程序和操作系统组件。
这种隔离的实现是,为每个应用程序分配单独的 Unix
用户(UID)和组(GID)标识符。 这种架构决策强制在单独的 Linux
进程中运行每个应用程序。 因此,由于在 Linux
中实现的进程隔离,在默认情况下,应用程序不能相互干扰,并且对操作系统提供的设施具有有限的访问。
因此,应用程序沙盒确保应用程序不能耗尽操作系统资源,并且不能与其他应用程序交互[3]。

澳门新葡亰网址下载 2

Linux
内核层提供的强制机制,有效地使用沙箱,将应用程序与其他应用程序和系统组件隔离。
同时,需要有效的通信协议来允许开发人员重用应用组件并与操作系统单元交互。
该协议称为进程间通信(IPC),因为它能够促进不同进程之间的交互。 在
Android 中,此协议在 Android 中间件层实现(在 Linux
内核层上发布的特殊驱动程序)。 此层级的安全性由 IPC 引用监控器提供。
引用监控器调解进程之间的所有通信,并控制应用程序如何访问系统的组件和其他应用程序。
在 Android 中,IPC 引用监控器遵循强制访问控制(MAC)访问控制类型。

默认情况下,所有 Android 应用都在低特权应用程序沙箱中运行。
因此,应用程序只能访问一组有限的系统功能。 Android
操作系统控制应用程序对系统资源的访问,这可能会对用户体验造成不利影响[3]。
该控制以不同的形式实现,其中一些在以下章节中详细描述。
还有一部分受保护的系统功能(例如,摄像头,电话或 GPS
功能),其访问权限应该提供给第三方应用程序。
然而,这种访问应以受控的方式提供。 在 Android
中,这种控制使用权限来实现。 基本上,每个提供受保护系统资源的访问的敏感
API 都被分配有一个权限(Permission)- 它是唯一的安全标签。
此外,受保护特性还可能包括其他应用的组件。

为了使用受保护的功能,应用程序的开发者必须在文件AndroidManifest.xml中请求相应的权限。
在安装应用程序期间,Android
操作系统将解析此文件,并向用户提供此文件中声明的权限列表。
应用程序的安装根据“全有或全无”原则进行,这意味着仅当接受所有权限时才安装应用程序。
否则,将不会安装应用程序。 权限仅在安装时授予,以后无法修改。
作为权限的示例,我们考虑需要监控 SMS 传入消息的应用程序。
在这种情况下,AndroidManifest.xml文件必须在<uses-permission>标签中包含以下声明:android.permission.RECEIVE SMS澳门新葡亰网址下载,。

应用程序尝试使用某个功能,并且该功能尚未在 Android
清单文件中声明,通常会产生安全性异常。
在下面几节中我们会讲解权限实现机制的细节。

令牌

其他类似的沙箱项目面临的一个问题是,限制程度应当如何,才能使得令牌和作业同时还保持有正常的功能。在Chromium沙箱里,对于Windows
XP最严格的令牌如下:

普通组

登录 SID : 强制

其他所有SID : 仅拒绝, 强制

限制组

S-1-0-0 : 强制

特权

正如上面所述的警告,如果操作系统授予了这样一个令牌,几乎不可能找到存在的资源。只要磁盘根目录有着非空的安全性,即使空安全的文件也不能被访问。在Vista中,最严格的令牌也是这样的,但它也包括了完整性级别较低的标签。Chromium渲染器通常使用这种令牌,这意味着渲染器进程使用的大部分资源已经由浏览器获取,并且他们的句柄被复制到了渲染器进程中。

注意,令牌不是从匿名令牌或来宾令牌而来的,它继承自用户的令牌,因此与用户的登录相关联。因此,系统或域名拥有的任何备用的审计仍然可以使用。

根据设计,沙箱令牌不能保护下面这些不安全资源:

  • 挂载的FAT或FAT32卷:
    它们上面的安全描述符是有效空。在target中运行的恶意软件可以读写这些磁盘空间,因为恶意软件可以猜测或者推出出它们的路径。
  • TCP/IP: Windows 200和Windows XP(但在Vista中不会)中的TCP/IP
    socket的安全是有效空。使得恶意代码与任何主机收发网络包成为可能。

关于Windows 令牌对象的更多信息可以在底部参考文献[02]查看。

Sandboxed API 怎么工作?

Sandboxed API 目前是针对用 C
语言编写的软件库实现的,未来可能增加更多编程语言的支持。

从高层次的角度看,Sandboxed API
将要加入沙箱的库和其调用者分成两个独立的操作系统进程:主机二进制文件和沙箱。具体的工作流程是:实际的库调用由主机端的
API 对象进行编组,通过进程间的通信发送到沙箱,沙箱的 RPC stub
会进行解组,并将调用转发到原始库。

澳门新葡亰网址下载 3

其中,API 对象(即图中的 SAPI 对象)和 RPC stub
都由项目提供,前者由接口生成器自动生成。用户只需提供沙盒策略、允许底层库进行的一组系统调用,以及允许访问和使用的资源。这些准备好了之后,基于沙盒
API 的库就可以轻松地在其他项目中重用了。

生成的 SAPI 对象的 API 类似于原始库的
API,不过会有额外的代码出现。这些代码用来设置沙箱,以及将内存传入和传出沙箱。但除此之外,代码流保持不变。

第一章 Android

来源:Yury Zhauniarovich |
Publications

译者:飞龙

协议:CC BY-NC-SA
4.0

Android 安全架构的理解不仅帮助我了解 Android
的工作原理,而且为我开启了如何构建移动操作系统和 Linux 的眼界。
本章从安全角度讲解 Android 架构的基础知识。 在第 1.1 节中,我们会描述
Android 的主要层级,而第 1.2
节给出了在此操作系统中实现的安全机制的高级概述。

  • 不要重新发明轮子:
    用更好的安全模型扩展操作系统内核很有诱惑力。但不要这样做。让操作系统在所控制的对象上应用它的安全策略。另一方面,创建有自定义安全模型的应用程序层级对象是可以的。
  • 最小权限原则:
    这既应该用于沙箱代码也应该用于控制沙箱的代码。换言之,即使用于不能提升权限到超级用户,沙箱也需要能够工作。
  • 假定沙盒代码是恶意代码:
    出于威胁建模的目的,我们认为沙箱中的代码一旦执行路径越过了一些main()函数的早期调用,那么它是有害的(即,它会运行有害代码),实践中,在第一外部输入被接收时,或者在进入主循环前,这就可能发生。
  • 敏感:
    非恶意代码不会尝试访问它不能获得的资源。在这种情况下,沙箱产生的性能影响应该接近零。一旦敏感资源需要以一种控制行为访问时,一点性能损失是必要的。这是在操作系统安全合适事情情况下的常见例子。
  • 仿真不是安全:
    仿真和虚拟机方案本身不能提供安全。沙箱不会出于安全目的,依赖于代码仿真,或者代码转换,或者代码修复。

沙箱是什么?

许多软件项目需要处理到外部数据,在安全方面会显得有些不足。当解析外部数据的软件库足够复杂时,软件会存在着严重的安全隐患,容易成为安全漏洞的受害者,从而遭遇内存损坏或是像路径遍历的逻辑解析问题。

一般的做法是将软件隔离,这个过程就是“沙箱”。通过“沙箱”,开发人员可以确保在解析用户生成内容涉及的代码时,只访问必要的资源(文件、网络连接和其他操作系统资源)。最坏的情况下,当潜在的攻击者取得软件项目范围内的远程代码执行权限时,沙盒技术可以将这些部分包含,从而保护其余的软件基础结构。

澳门新葡亰网址下载 4

沙盒技术必须具有很强的抵御攻击能力,从而充分保护操作系统的其余部分。同时沙箱必须足够易于使用,以供软件开发人员使用。为了帮助完成这项任务,谷歌开源了
Sandboxed
API,一个经过实战考验的项目,可以为各个软件库创建安全策略。

Sandboxed API
用于访问沙盒库中的各个软件功能,也因此谷歌还公开了核心沙盒项目
Sandbox2。Sandbox2
现在是 Sandboxed API
的一部分,提供了底层的沙盒原型。它也可以单独用于隔离任意 Linux
进程,可以视为更低级的 API。

如果你不想要阅读这整个文档,你可以阅读Sandbox
FAQ。沙箱保护与不保护的内容也可以在FAQ中找到。

目标进程

在Chromium中,渲染器总是target进程,除非浏览进程被指定了–no-sandbox命令行参数。target进程维护所有将在沙箱中允许的代码,以及沙箱基础设施的客户端:

  1. 所有代码沙箱化
  2. 沙箱IPC客户端
  3. 沙箱策略引擎客户端
  4. 沙箱拦截

第2,3,4条是沙箱库的一部分,与需要被沙箱化的代码关联。

拦截器是通过沙箱转发的Windows API调用。由broker重新发出API
调用,并返回结果或者干脆终止调用。拦截器+IPC机制不能提供安全性;它的目的是在沙箱中的代码因沙箱限制不能修改时,提供兼容性。为了节省不必要的IPC,在进行IPC调用前,target中进程策略也会被评估,尽管这不是用作安全保障,但这仅仅是一个速度优化。

期望在未来大部分plugin会运行在target进程里。

澳门新葡亰网址下载 5

在它的核心,沙箱依赖于4个Windows提供的机制:

  • 限定的令牌
  • Windows工作对象
  • Windows桌面对象
  • Windows Vista及以上:集成层

这些机制在保护操作系统,操作系统的限制,用户提供的数据上相当的高效,前提是:

  • 所有可以安全化的资源都有一个比null更好的安全描述符。换言之,没有关键资源会有错误的安全配置。
  • 计算机并未被恶意软件所损害。
  • 第三方软件不能弱化系统安全。

**
注意:上面具体的措施以及在内核外的措施会在下面的“进程轻量化”部分阐述。**

信用等级

信用等级在Windows
Vista及其之后的版本可用。它们不会用严格的方式定义安全的边界,但他们确实提供了一种强制访问控制,并且作为微软IE沙箱的基础而存在。

信用等级由一个特殊的SID和ACL对的集合实现,它们代表了五种递增等级:不受信任的,低级的,中级的,高级的,系统的。如果一个对象处于比请求令牌更高级的信用等级,访问它就会受限。信用等级也实现了用户界面权限隔离,这种隔离应用了信用等级规则,让同一个桌面中的不同进程可用交换窗口消息。

默认情况下,令牌可以读高信用等级的对象,但不能写。大多数桌面应用运行在中信用等级,而较不受信任的进程像IE保护模式和我们自己的沙箱运行在低信用等级。一个低信用等级模式的令牌只可以访问下面这些共享资源:

  • 对大部分文件可以做读访问
  • 对%USER PROFILE%、AppData、LocalLow目录的写访问
  • 读注册表的大部分内容
  • 对HKEY_CURRENT_USERSoftwareAppDataLow目录做写访问
  • 剪贴板(为某些格式做复制粘贴)
  • 远程过程调用
  • TCP/IP Socket
  • 通过ChangeWindowMessageFilter暴露窗口消息
  • 通过LI标签共享内存
  • 拥有LI启动激活的权限,访问COM接口
  • 通过LI标签暴露的命名管道

你会注意到之前描述的令牌属性,工作对象,额外的桌面限制性更大,并且事实上会阻碍对上面列出的所有东西的访问。所以,信用等级比其他措施更宽松,但这也可以被视为一种对深度防御的否定,并且,它的使用对性能或者资源使用不会有明显的影响。

更多关于信用等级的信息可以在底部参考文献[03]找到。

沙盒利用操作系统提供的安全性,允许不能对计算机做出持久性改变或者访问持续变化的信息的代码的执行。沙箱提供的架构和具体保证依赖于操作系统。这个文档覆盖了Windows实现与一般的设计。Linux实现和OSX实现也会在这里描述。

Windows沙箱是一种仅用户模式可用的沙箱。没有特殊的内核模式驱动,用户不需要为了沙箱正确运行而成为管理员。沙箱设计了32位和64位两种进程,在所有windows7和windows10之间的所有操作系统版本都被测试过。

作业对象

target进程也运行着一个作业对象。使用这个Windows机制,一些有趣的,不拥有传统对象或者不关联安全描述符的全局限制可以被强制执行:

  • 禁止用SystemParametersInfo()做用户共享的系统范围的修改,这可以用于切换鼠标按钮或者设置屏幕保护程序超时
  • 禁止创建或修改桌面对象
  • 禁止修改用户共享的显示设置,比如分辨率和主显示器
  • 禁止读写剪贴板
  • 禁止设置全局Windows hook(使用SetWindowsHookEx
  • 禁止访问全局原子表
  • 禁止访问在作业对象外创建的USER句柄
  • 单活跃的进程限制

Chromium渲染器在激活所有这些限制的情况下允许。每个渲染器运行在自己的作业对象里。使用作业对象,沙箱可以避免:

  • 过度使用CPU周期
  • 过度使用内存
  • 过度使用IO

有关Windows作业对象的详细信息可以在底部参考文献[1]中找到。

额外的桌面对象

令牌和作业对象定义来一个安全边界:即,所有的进程有着相同的令牌,同一个作业对象中所有进程也处于同样的安全上下文。然而。一个难以理解的事实是相同桌面上都有窗口上的应用程序也处于相同的安全上下文中,因为收发window消息是不受任何安全检查。通过桌面对象发送消息是不允许的。这是臭名昭著的“shatter”攻击的来源,也是服务不应该在交互桌面上托管窗口的原因。Windows桌面是一个常规的内核对象,它可以被创建然后分配一个安全描述符。

在标准Windows安装中,至少两个桌面会与交互窗口站相关联,一个是常规桌面,另一个是登录桌面。沙箱创建了第三个与所有target进程关联的桌面。这个桌面永远不可见,也不可交互,它有效地隔离了沙箱化进程,使其不能窥探用户的交互,不能在更多特权的环境下发送消息到Windows。

额外的桌面对象唯一的优点是它从一个隔离的池使用接近4MB的内存,在Vista里可能更多。

全书地址Chromium中文文档 for

安全是Chromium最重要的目标之一。安全的关键在于理解下面这点:在我们完整地理解了系统在所有可能的输入组合下表现出的行为之后,我们才能够真的保证系统安全。对于像Chromium这样庞大而多样化的代码库,推理它的各个部分可能的行为的组合几乎是不可能的。沙箱的目标是提供这样一种保证:不论输入什么,保证一段代码最终能或不能做的事情。

进程轻量化策略

大多数进程轻量化策略可以可以通过SetProcessMitigationPolicy方法应用于Mtarget进程。沙箱使用这个API为target进程设置不同的各种策略,以强化安全特性。

重定位图像:

  • >= Win8
  • 在进程中对所有图片做随机地址加载(必须被所有图片支持)

堆之终结:

  • >= Win8
  • 结束Windows堆占用进程

自底向上ASLR:

  • >= Win8
  • 设置随机的下界作为进程的最小用户地址

高熵值ASLR:

  • >= Win8
  • 为自底向上ASLR增加随机等级到1TB。

严格句柄检查:

  • >= Win8
  • 对于恶意句柄引用立即抛出异常

Win32k.sys锁定:

  • >= Win8
  • ProcessSystemCallDisablePolicy,允许选择性关闭target进程可用的系统调用
  • 渲染器进程现在把这个功能设置到了DisallowWin32kSystemCalls上,这意味着win32k.sys用户模式的调用不再被允许。这极大地减少了来自渲染器的可用的内核攻击。查看这里获取更多细节。

App容器(Low Box Token):

  • >= Win8

  • 在Windows里,这由内核层的一个Low Box
    Token实现,它是有着限制优先权(通常只有SeChangeNotifyPrivilege和
    SeIncreaseWorkingSetPrivilege)的一个剥离版本,运行在低信用等级,这个容器还由一组“能力”实现,它们可以映射到进程允许/拒绝做的事情(查看MSDN获取更详细的描述)。从沙箱角度看,最有趣的能力是否决是对网络的访问,如果令牌是Low
    Box Token,INTERNET_CLIENT能力没有出现的话,就会执行网络检查。

  • 因此沙箱对已有的限制令牌,添加了Low
    Box相关的属性,并且不授予任何能力,以获得没有来自沙箱化进程的网络访问这样的额外的网络保护。

禁用字体加载:

  • >= Win10
  • ProcessFontDisablePolicy

禁用远程设备图像加载:

  • >= Win10 TH2
  • ProcessImageLoadPolicy
  • 例:网络资源的UNC路径

禁用“强制低信用等级”的图像加载:

  • >= Win10 TH2
  • ProcessImageLoadPolicy
  • 例:临时Internet文件

禁用额外的子进程创建:

  • >= Win10 TH2
  • 如果作业等级<=
    JOB_LIMITED_USER,用UpdateProcThreadAttribute()设置PROC_THREAD_ATTRIBUTE_CHILD_PROCESS_POLICY为PROCESS_CREATION_CHILD_PROCESS_RESTRICTED。
  • 这是额外层面的防御,使得作业层可以从外部打破。[引用: ticket,
    Project Zero blog.]

其他警告

操作系统可能有一些bug。令人感兴趣的是Windows
API中允许跳过常规安全检查的一些bug。如果存在这样的bug,恶意软件能够穿透安全限制,broker策略,并且可能危害计算机。在Windows环境下,没有实用的方式可以避免沙箱中的代码调用系统服务。

另外,第三方软件,尤其是反病毒解决方案,可能创建新的攻击角度。最麻烦的是为了使用一些(通常是系统不愿其使用的)功能,注入动态链接库的应用程序。这些动态链接库也会注入到沙箱进程中。在最好的情况下,他们会产生故障,在最糟的情况下,可能为其他进程或文件系统本身造出后门,让精心设计的恶意软件逃离沙箱。

应用与target进程的真实限制通过策略设置。这些策略只是一种broker调用的编程接口,它们定义了限制与权限。四个函数控制这种限制,对应四种Windows机制:

  • TargetPolicy::SetTokenLevel()
  • TargetPolicy::SetJobLevel()
  • TargetPolicy::SetIntegrityLevel()
  • TargetPolicy::SetDesktop()

前三个调用接收从非常严格到非常宽松的整数等级参数,例如令牌有七个等级,作业有五个等级。Chromium渲染器通常运行四种机制中最严格的模式。最后,桌面策略有两种,只能用于表示一个target进程是否运行在额外的桌面对象中。

这些限制是粗糙设计的,因为它们会影响目标可访问的所有可保护资源,但有时我们需要更精细粒度的分辨能力。沙箱策略接口允许broker指定例外的情况。一个例外是,在target中发出特定Windows
API调用,将其代理给broker的方式。broker可以检查参数,使用不同的参数重新发出调用,或者干脆拒绝调用。为了指定例外情况,需要有一个独立的调用:AddRule。现在支持以下几种针对不同的Windows子系统的规则:*文件*命名管道*进程创建*登记*同步对象

每种子系统的具体形式各不相同,但通常规则会基于字符串模式得到触发。例如,一种可能的文件规则是:

AddRule(SUBSYS_FILES, FILES_ALLOW_READONLY, L"c:\temp\app_log\d*.dmp")

这个规则指定了当一个target进程想要打开文件时,可以授予的权限,以及匹配字符串格式的文件的只读权限;例如
c:tempapp_logdomino.dmp是一个满足上面那种格式的文件。查询头文件可以获得最新支持的对象与行为的列表。

规则只能在每个进程产生前添加,当target运行时不能修改,但不同的target可以有不同的规则。

Target不会从策略定义的限制开始执行。他们从与常规用户进程拥有的令牌非常接近的一个令牌开始执行。因为在进程引导的过程中,操作系统加载器会访问大量的资源,其中大部分是未认证且随时会变化的。另外,大部分应用程序使用标准开发工具提供的标准CRT,在进程得到引导后,CRT也需要初始化,这时CRT初始化的内部再次变成未认证状态了。

因此,在引导阶段,进程实际上使用了两种令牌:锁定令牌,也是进程令牌,还有初始令牌,被设置为初始线程的模拟令牌。事实上,真正的SetTokenLevel定义是:

SetTokenLevel(TokenLevel initial, TokenLevel lockdown)

在所有的初始化操作完成后,main()或WinMain()会继续执行,还有两个令牌会存活,但只有初始线程可以使用更强大的那个初始令牌。target的责任是在准备完成后销毁初始令牌。通过下面这个简单的调用实现:

LowerToken()

在target声明这个调用之后,唯一可用的令牌是锁定令牌,完整的沙箱限制开始生效。这个调用不可以撤销。注意初始令牌是一个模拟令牌,它只对主线程有效,target进程创建的其他线程只使用锁定令牌,因此不会尝试获取任何需要安全检查的系统资源。

target始于特权令牌的事实简化了显式策略,因为任何特权相关的需要在进程启动时一次完成的东西,可用在LowerToken()调用前完成,并且不需要在策略中设置规则。

重要

请确保初始令牌获取的任何敏感操作系统句柄在调用LowerToken()前关闭。任何泄露的句柄可能被恶意软件利用以逃离沙箱。

[01] Richter, Jeffrey “Make Your Windows 2000 Processes Play Nice
Together With Job Kernel Objects”

[02] Brown, Keith “What Is a Token”

[03] Windows Integrity Mechanism Design

沙箱在进程级粒度进行运作。凡是需要沙箱化的任何东西需要放到独立进程里运行。最小化沙箱配置有两个过程:一个是被成为broker的权限控制器,以及被称为target的一个或多个沙箱化进程。在整个文档和代码中这两个词有着上述两种精确的内涵。沙箱是一个必须被链接到broker和target可执行程序的静态库。

broker进程

在Chromium中,broker总是浏览进程。broker,广泛概念里,是一个权限控制器,沙箱进程活动的管理员。broker进程的责任是:

  1. 指定每个目标进程中的策略
  2. 生成目标进程
  3. 维护沙箱策略引擎服务
  4. 维护沙箱拦截管理器
  5. 维护沙箱IPC服务(与target进程的通信)
  6. 代表目标进程执行策略允许的操作。

broker应该始终比所有它生成的目标进程还要活的久。沙箱IPC是一种低级别的机制(与ChromiumIPC机制不同),这些调用会被策略评估。策略允许的调用会由broker执行,结果会通过同样的IPC返回给目标进程。拦截管理器是为应该通过IPC转发给broker的windows
API调用提供补丁。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图