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

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 应用广泛,但是没有暴露给用户态。

  • BSD的MALLOC 和 zone :BSD 的malloc 系列函数<bsd/sys/malloc.h> 头文件中。函数名为_MALLOC、_FREE、_REALLOC、_MALLOC_ZONE、_FREE_ZONE
  • mcache 和 slab 分配器:这是BSD 提供的基于缓存的非常高校的内存分配方法,默认是实现是使用任何后端 slab 分配器。使用mcache 机制的主要优点是速度:内存分配和维护是在每一个 CPU 自有的缓存中进行的,因此可以映射到CPU的物理缓存,从而极大地提升访问速度
内存压力

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)的基础机制。工作队列是通过两个系统调用提供的:

  • workq_open( ):创建一个工作队列,LibC 中的 pthread_workqueue_create_np 函数封装了这个系统调用,而这个库函数进一步被GCD 和 libdispatch 中的 dispatch_get_global_queue 函数封装了
  • workq_kernturn( ):负责创建工作队列以外的其他所有的事情,通过以下3个定义选项对工作队列进行控制:
  • WQOPS_QUEUE_ADD:对应的是要执行(用GCD 的话说就是分发(dispatch))的代码块(block)或函数。libdiapatch 实际上对每一个队列都创建了两份副本,额外的那一份副本用于overcommit(过量使用),不过这些额外的副本没有直接暴露给调用者。通过这种方式,应用程序的主队列实际上只不过是默认队列的引用,并且设置了overcommit。overcommit位表示这个队列可以创建新的线程,通常情况下不建议使用这个策略,因为线程多于CPU数会降低程序的运行速度,GCD将通过dispatch_get_global_queue 调用可以接受的一个标志(DISPATCH_QUEUE_OVERCOMMIT)来支持overcommit,但是苹果的文档掩盖了这个事实,宣传这个标志必须为0
  • WQOPS_THREAD_SETCONC:控制工作队列的并发性,pthread_workqueue_requestconcurrencu_np( ) 调用封装了这个选项
  • WQOPS_THREAD_RETURN:将线程从工作队列分开并终止线程。pthread 的 workqueue_exit( ) 调用通过一个内部调用_thread_workq_return 封装了这个选项
    工作队列设置(由项的添加而出发)的逻辑在XNU 中非常独特。主要工作由 wq_runitem 完成的,wq_rnitem 调用 setup_wqthread 手工创建了工作队列线程的状态,设置了每一个寄存器的值。然后唤醒线程,线程以新的身份运行

换个角度看BSD层

sysctl

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

kqueue

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

  • kqueue(#362):负责创建kqueue,创建的keque实际上是一个文件描述符
  • kevent/kevent64(#363和#369):用于设置事件过滤器以及从kqueue 中读取事件
审计(OS X)

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

  • AUDIT_SYSCALLL_ENTRY:调用sysent 表中的一条UNIX 系统调用之前调用这个宏。这个宏接受3个参数:系统调用代码(编号)、BSD进程以及负责这个调用的线程对象
  • AUDIT_ARG:在系统调用的实现内部调用。这个宏接受一个表示操作的参数,以及其他可变参数,其他参数具体取决于对应的系统调用
  • AUDIT_SYSCALL_EXIT:在系统调用的实现之后立即被调用。参数和ENTER的参数值,还接受一个系统调用的返回值
强制访问控制(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的命名约定,其中:

  • object:表示对象类型:file(实际上是文件描述符)、port、socket、sysvsem、proc 和 vnode(文件本身)
  • operation:可以是“label”和“check”。“label”操作表示标签相关的操作。“check”操作表示认证一个系统调用或陷阱
  • call:对于check,通常表示访问检查涉及的系统调用(或Mach陷阱)名称;对于label,则表示标签声明周期的一个阶段,通常包括init、associate 和 destory,有时候还要其他特定的动词

当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,有用的函数包括:

  • mpo_vnode_chek_exec:这个AMFI的回调函数返回1(表示允许vnode执行),但是不会在设置代码签名的标志位(CS_HARD和CS_KILL)之前返回1。这可以确保所有的进程都必须进行代码签名的检查,而且之后如果需要代码检查的话也能杀掉进程
  • mpo_vnode_check_signature:这是AMFI的主逻辑,这个函数使用了amfid以其内核内的签名缓存来验证文件的代码签名
  • mpo_proc_check_get_task:这个函数保护task_for_pid 调用,作用是获得任务的端口(从而能完全控制任务)。这个函数检查两个entitlement(get-taks-allow 和task-for-pid-allow),还有一个调用用于检查是否启用了不受限制的调试(通过amfid),如果上诉任何返回真,那么这个函数也返回真
  • mpo_proc_check_run_cs_invalid:检查是否设置了entitlement:get-task-allow、run-invalid-allow以及run-unsigned-code,或者是否启用了不受限制的调试。如果检查返回真,那么cs_allow-invalid清除CS_KILL、CS_HARD和CS_VALID位,并且返回真,允许执行未签名的代码

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事事都要插手
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,646评论 4 366
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,979评论 1 301
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 110,391评论 0 250
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,356评论 0 215
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,740评论 3 293
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,836评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,022评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,764评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,487评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,728评论 2 252
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,200评论 1 263
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,548评论 3 260
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,217评论 3 241
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,134评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,921评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,919评论 2 283
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,766评论 2 274

推荐阅读更多精彩内容