深入解析Mac OS X & iOS 操作系统 学习笔记

2016-11-10  本文已影响2546人  CoderKo1o

BSD 高级功能

内存管理

虚拟内存管理是在Mach 层进程的,Mach 控制了分页器,并且向用户态导出了各种vm_和mach_vm_消息接口。而用户态的开发者大部分都只知道标准的POSIX 调用,因此需要对这些Mach 调用进行封装。BSD也使用了属于自己的内存管理函数。

POSIX 内存和页面管理系统调用

POSIX 为开发人员提供了多种API,用于虚拟内存页面的管理和严格控制。函数所在的头文件为<sys/mman.h>这些函数是对Mach VM 原语的包装,因为Mach VM 原语才真正负责处理Mach 虚拟内存。这些函数执行基本的参数肩擦,然后通过current_map( ) 获得当前的Mach 内存映射,最后再调用底层的Mach 函数。

BSD 内部的内存函数

BSD 层要求有自己的内存管理函数,这些函数自然是架构在Mach 之上。这些函数在XNU 的BSD 应用广泛,但是没有暴露给用户态。

内存压力

Mach VM 层支持 VM 压力(pressure)的概念,这个概念表示的意思是系统的可以RAM量低到危险的程度了。VM压力的处理放在BSD 层进程,BSD层还提供了一个系统调用 vm_pressure_monitor( ),这个调用直接封装了Mach对应的调用。当系统发送内存压力通知,iOS 中的 Objective-C 应用就会响应。Objective-C的垃圾回收机制使用了libauto,libauto调用libdispatch 创建一个VM 压力分发源,还会调用应用程序提供的didReceiveMemoryWarning回调函数。

Jestam/Memorystatus(iOS)

进程并不是总能找到可以抛弃的内存时,这时需要采用Jestam机制。这是OS X 和 iOS 实现的一个低内存清晰的处理机制。也称为Memorystatus,这个机制有点类似于Linux的“Out-of-Memory”杀手,最初的目的就是杀掉消耗太多内存的进程。Memorystatus维护了两个列表:

进程休眠(iOS)

在iOS 5中,Jstsam/Memorystatus 和默认的freezer 结合在一起,实现了对进程的冷冻而不是杀死。通过这种方式可以提供更好的用户体验,因为数据不会丢失,而且当内存情况好转时进程可以安全恢复。进程休眠操作是有jstsam_hibernate_top_proc 完成的,这个函数冷冻底层的任务(通过task_freeze)。冷冻操作需要遍历任务的vm_map,然后将vm_map 传递给默认的 freezer。用户态也可以通过pid_suspend( ) 和 pid_resume( )控制进程的休眠。iOS 还定义了 pid_hibernate,这个函数目前会忽略传入的参数,仅仅唤醒kernel_hibernation_thread(即通过kern_hibnernation_wakeup发送信号)。

内核地址空间布局随机化(ASLR)

这项技术是在 Mountain Lion 引入的。现在已经成为操作系统想要阻止黑客和恶意软件视图注入代码攻击的必备技术。防御代码注入的主要方法是数据执行阻止(Data Execution Prevention,DEP,在Intel 中也称为W^X或XD,在ARM中也称为XN),DEP能使得黑客注入代码的企图更加困难。

工作队列

工作队列(work queue)是OS X 中开发的一项机制,作用是为用户通讯提供多线程并且支持扩展到多处理器支持。工作队列也是苹果Grand Central Dispatch(GCD)的基础机制。工作队列是通过两个系统调用提供的:

换个角度看BSD层

sysctl

BSD 和很多其他UNIX 系统一样,也提供了一个统一的接口用于获取和设置内核变量,这个接口称为sysctl(8)。而和Linux 这样的系统不同之处在于,sysctl 是访问这些变量的唯一方法,因为缺少/proc这样用户可以见的文件系统。

kqueue

BSD 中引入 kqueue 的目的是为了替代伸缩性不好的poll(2)/select(2)模型。这个接口着重强调的方面是扩展性,允许未来添加任意数目的事件源,而不需要对编程接口进行修改。XNU 导出了两个和kqueue相关的系统调用:

审计(OS X)

从内核角度看,审计只不过是在系统调用的逻辑中穿插了一些宏的过程:

强制访问控制(MAC)

强制访问控制(Mandatory Access Control,MAC),这是苹果从TrustedBSD 引入的一项强大的安全特性。用户态的视角非常有局限性,只有内核才能可靠地实施这种安全性。

MAC策略

从用户态看,MAC策略只不过是一个不透明的对象。然而在内核态中,策略是一个mac_policy_conf数据结构。策略模块在加载时通过mac_policy_register注册这个数据机构,在退出时应该通过mac_policy_unregister解除注册这个结构。
mac_polic_conf 数据结构中的关键字段是 mpc_ops,这是一个指向mac_policy_ops 数据结构的指针。mac_policy_ops 数据结构是一个包含了300多个函数指针的巨大结构体,每一个策略模块都应该实现其中的函数或留空(NULL)。这些函数指针基本上覆盖了系统中的每一个操作,函数名遵循mpo_object_operation_call的命名约定,其中:

当XNU 调用MAC层验证一个操作时,MAC层调用策略模块,然后策略模块负责进行验证。所有的MAC检查基本上都符合一个模板。例如,考虑一个非常有用的mac_vnode_check_signature操作,这个操作负责实施代码签名。

苹果的策略模块

OS X 中 MAC 的主要作用是沙盒机制,在iOS中通过MAC实现严格的代码签名和entitlement机制,使得苹果可以保护自己珍贵的硬件不被可怕的第三方代码破坏。

sandbox.kext

sandbox 内核扩展有时候会请求/usr/libexec/sandboxd的服务。这个守护程序是有launchd(1)启动的,使用的主机特殊端口#14(通过HOST_SEATABELT_PORT定义)。sandbox.kext 实现了一个小型的类SCHEME方言,用于定义认证和操作许可。这个文本格式在用户态动态编译,然后提交给内核用作之后的验证。验证则是另一个内核扩展AppleMatch.text的职责,AppleMatch.kext 负责规则和正则表达式匹配

AppleMobileFileIntegrity.text

iOS 的安全机制比 OS X 的安全机制要严格得多。 OS X 中的代码签名是可选的,而iOS 会通过 kill -9 杀掉任何代码签名不正确的进行。iOS 中的“坏警察”的职责是由AppleMobileFileIntegrity.kext(AMFI)扮演的。AMFI在用户态有一个守护程序:/usr/libexec/amfid。这个守护程序是有launchd 启动的,也注册了一个主机特殊端口#18(HOSR_AMFID_PORT)。这个守护程序接收来自AMFI的消息,并且负责AMFI完成一些最好在用户态完成的任务。
对initializeAppleMobileFileIntegrity函数调用了mac_policy_register,就像所有的策略模块一样。这个模块大部分回调函数都是NULL,有用的函数包括:

AMFI能(通过PE_parse_boot_argn)识别一些引导参数,并且根据参数禁用一些检查。如下表:

AMFI引导参数 用途
PE_i_can_has_debugger 这个XNU中使用的全局引导参数,表示允许附着调试器。禁用大多检查
cs_debug 禁用代码签名
cs_enfoecement_disable 禁用代码签名;仍然会做检查,但是仅此而已
amfi_allow_any_signature 允许任何代码签名,不仅是苹果的签名
amfi_unrestrict_task_for_pif 不论进程是否有get-task-allow和task_for_pid-allow entitlement,都允许task_for_pid
amfi_get_out_of_my_way 整个禁用AMFI。明显是苹果的开发者原卷了AMFI事事都要插手
上一篇 下一篇

猜你喜欢

热点阅读