首页
社区
课程
招聘
[原创]CVE-2020-27950 trailer->msgh_ad内核信息泄露
发表于: 2021-2-3 13:00 82377

[原创]CVE-2020-27950 trailer->msgh_ad内核信息泄露

2021-2-3 13:00
82377

公告

跟着这篇文章复现CVE-2020-27950内核信息泄露漏洞

第一次通过bindiff补丁对比逆向分析iOS内核漏洞,踩了不少坑,如果各位师傅有更好的分析办法可以多指点

我们选用iPhone 6的两个固件版本:12.4.8和12.4.9

漏洞版本iOS 12.4.8 (16G201) for iPhone 6

补丁版本iOS 12.4.9 (16H5) for iPhone 6

这两个固件都是ZIP压缩文件

解压缩出来,kernelcache.release.iphone7就是压缩后的内核二进制文件

iPhone 6使用的是LZSS压缩算法

我们对其进行解压缩,使用的工具是lzssdec

下载编译

解压缩kernelcache文件,现在我们获得了一个存在漏洞的固件版本,同理获取打补丁后的固件版本

现在漏洞版本和补丁版本的kernelcache文件都准备好了

通过bindiff进行补丁对比,bindiff现在已经更新到了6

因为一些大家都懂得的原因,Windows的IDA目前有最新的7.5,而macOS只有7.0,如果是IDA 7.0,目前只能使用bindiff 5,如果是7.5,开心的使用bindiff 6吧

macOS版本有一个错误需要提前解决掉

为了使用更多的特性以及更准确的分析结果,我决定使用IDA 7.5

将两个文件载入IDA 7.5进行分析,生成idb文件,再通过bindiff分析这两个idb文件

图片描述

关于符号恢复这部分的一波三折大家可以看这篇文章《关于恢复kernelcache符号的问题》,记录了我这几天是如何踩坑的

首先比对kc_12.4.8kc_12.4.9,得到八个差异函数,再逐个反编译查看代码,发现有五个函数是添加了同一段代码

现在记录者五个跟漏洞有关的函数,再用kc_12.4.8和一个泄露符号的kc_symbols,分别搜索前面记录的五个函数,通过bindiff的方式恢复出了两个正确的符号

剩下三个函数其中一个具有字符串,搜索源码发现是ipc_kobject_server(),此时剩下两个函数找不到符号

同时搜索补丁代码中的sub_FFFFFFF00766D6C0,确定是函数bzero()

图片描述

到这一步为止,我们勉强和作者拥有了同样的漏洞分析起点

我们开始分析XNU源码,先从三个有符号的函数任选一个进行分析,我选择了函数ipc_kmsg_get()

前两天刚好开源了最新的xnu-7195.50.7.100.1

再来一个早一点的版本xnu-6153.141.1

源码一对比,果然多了函数bzero()的调用

左边是漏洞版本,右边是补丁版本

图片描述

补丁操作的变量trailer类型是mach_msg_max_trailer_t,而mach_msg_max_trailer_t是由mach_msg_mac_trailer_t定义而来

mach_msg_mac_trailer_t是一个结构体,在这个结构体定义附近发现了两个宏:MACH_MSG_TRAILER_MINIMUM_SIZEMAX_TRAILER_SIZE,分别代表最大的trailer和最小的trailer长度,由此我们可以找到结构体mach_msg_trailer_t的定义

从结构体定义可以看到,最大的trailer拥有好几个字段,长度为0x44,而最小的trailer结构体只有两个字段,长度为0x08

我喜欢结合函数功能来讲一个漏洞,比如它是什么作用,在哪里调用到,用户态可控的数据有哪些

比如这个漏洞的补丁,什么是trailer?什么操作能调用到这段代码?

作为入门选手,想要从我说的角度去理解这个漏洞,就需要先来学习下基础知识

Mach是XNU内核的内核,它实现了操作系统最基本的功能:进程和线程抽象,虚拟内存管理,任务调度,进程间通信和消息传递机制

BSD实现于Mach之上,包括:网络协议栈,文件系统访问,设备访问等等

以上来自《深入解析Mac OS X & iOS操作系统》第二章

在Mach中有一个很基本的概念叫作Message,也就是消息,消息在两个Port之间传递,消息分为Simple MessageComplex Message,作为复杂消息,自然包含的字段数据要比简单消息要多

Port简单可以理解为一个内核的消息队列,Task创建一个Port后,只有该Task对这个Port有接收消息的Right,其它Task都可以在获取发送Right后对该Port发送消息

Mach Message的接收与发送依赖函数mach_msg()进行,这个函数在用户态与内核态均有实现

一条基本的消息由Message HeaderMessage Body构成,它可以选择带上消息尾,也就是上面提到的trailer

以上来自《深入解析Mac OS X & iOS操作系统》第十章

有了一些基本概念之后,我们尝试从开发角度来使用Mach Message

创建Receiver Port并等待接收消息

首先我们要创建分配一个Port

获取往Port发消息的Right

向系统注册该Port,这样其它进程都可以通过对应的名字搜索到该Port

通过函数mach_msg()阻塞线程等待接收消息

注意trailer在此处的使用,trailer可以附加在消息尾部作为额外的请求,trailer不计算入消息头的msgh_size,它有自己的长度字段msgh_trailer_size,此处使用的是最小的空trailer

获取Sender Port并向其发送消息

搜索并获取指定Port

构造消息

此处是发送消息,注意第二个参数

到此完成Mach Message的接收与发送流程

如果有兴趣可以详读这两篇文章,第一篇的代码没有问题,但是第二篇的代码有点过时了,我没有运行起来

我们来看如何在这个过程中发挥trailer的作用,将mach_msg_trailer_t改为mach_msg_security_trailer_t,同时修改函数mach_masg()第二个参数

当收到消息,即可打印出发送消息者的信息

从这个过程可以看出来,Port接收者可以在调用函数mach_msg()时额外从内核指定获取一些数据

以上代码来自《Mac OS X技术内幕》第九章

函数mach_msg()第二个参数有如下的标志位,这个参数在内核里用option来表示

如果对于Mach Message发送与接收基本流程不理解的同学一定多看看上面这几段代码

以下假设大家对于Mach Message都有了一定的基本理解,并且删除了部分调试与失败返回处理代码

我们跟入函数mach_msg(),函数mach_msg()会调用函数mach_msg_trap(),函数mach_msg_trap()会调用函数mach_msg_overwrite_trap()

这里有两种我们需要分析的场景:MACH_RCV_MSGMACH_SEND_MSG

当函数mach_msg()第二个参数是MACH_SEND_MSG的时候,函数ipc_kmsg_get()用于分配缓冲区并从用户态拷贝数据到内核态

函数ipc_kmsg_get()属于漏洞函数,ipc_kmsg_t就是内核态的消息存储结构体,拷贝过程看注释

函数ipc_kmsg_get()结尾赋值trailer的时候,使用的是mach_msg_max_trailer_t,给kmsg申请的长度也是按照mach_msg_max_trailer_t计算,但只初始化了三个字段,其它字段并未初始化,这是漏洞成因之一

当函数mach_msg()第二个参数是MACH_RCV_MSG的时候,会调用函数mach_msg_receive_results()读取消息

函数mach_msg_receive_results()用于读取消息,如果消息读取成功,会调用函数ipc_kmsg_add_trailer()

函数ipc_kmsg_add_trailer()此时已经拿到整个kmsg,但是最后的trailer还是根据发送者的定义,此处需要结合接收者的请求去做动态修改msgh_trailer_size

REQUESTED_TRAILER_SIZE_NATIVE定义如下,逐个判断,匹配到哪个参数就是对应结构体长度

确实乍一看这里的计算方式没有问题,但我们来看一段宏定义,如果我们传入的是5或者6这种定义里没有的数据呢?

当我们传入的是5,计算出的位数据为0b111000000000000000000000010MACH_RCV_TRAILER_MASK的位数据为0b1111000000000000000000000000,也就是说,5可以通过MACH_RCV_TRAILER_MASK标志位的判断

回到函数mach_msg_receive_results(),上面计算到的trailer_size会在计算完成后传入函数ipc_kmsg_put(),这个函数主要用于将消息从内核态拷贝到用户态

注意看拷贝操作的长度变量size

总结一下,我们现在可以通过设置函数mach_msg()的第二个参数为MACH_RCV_MSG | MACH_RCV_TRAILER_ELEMENTS(5)来获取到最大的trailer->msgh_trailer_size,而且可以跳过trailer->msgh_ad的初始化

现在来看Poc代码

使用XCode调试,新建一个iOS应用,运行在12.4的iPhone 6上,把Poc代码插入运行

图片描述

我这里发现了一个XCode解析结构体的问题,按照结构体定义,我标出了msgh_audit的数组位置,在val[7]后面,是64位长度的msgh_context,但是这里解析出错,因为47148392572927344640x416e795300000000,修正结构体偏移后,在msgh_ad的位置上是我们提前设置的数据0x416e7953

现在成功泄露出内核数据

那我们如何泄露出一个有用的内核数据呢?

咱们下次再聊

关于符号的问题,我在漏洞复现结束后突发奇想,既然五个函数都有同样的问题,那么说明五个函数漏洞场景肯定是相同的,所以搜索以下这句代码

妥了,五个函数都在这里了

图片描述

Available for: macOS High Sierra 10.13.6, macOS Mojave 10.14.6
 
Impact: A malicious application may be able to disclose kernel memory. Apple is aware of reports that an exploit for this issue exists in the wild.
 
Description: A memory initialization issue was addressed.
 
CVE-2020-27950: Google Project Zero
Available for: macOS High Sierra 10.13.6, macOS Mojave 10.14.6
 
Impact: A malicious application may be able to disclose kernel memory. Apple is aware of reports that an exploit for this issue exists in the wild.
 
Description: A memory initialization issue was addressed.
 
CVE-2020-27950: Google Project Zero
 
 
➜  ~ file *.ipsw
iPhone_4.7_12.4.8_16G201_Restore.ipsw: Zip archive data, at least v2.0 to extract
iPhone_4.7_12.4.9_16H5_Restore.ipsw:   Zip archive data, at least v2.0 to extract
➜  ~ file *.ipsw
iPhone_4.7_12.4.8_16G201_Restore.ipsw: Zip archive data, at least v2.0 to extract
iPhone_4.7_12.4.9_16H5_Restore.ipsw:   Zip archive data, at least v2.0 to extract
➜  iPhone_4.7_12.4.8_16G201_Restore ls -al
total 6012560
drwxr-xr-x@  9 wnagzihxa1n  staff         288 Jan  2 19:41 .
drwxr-xr-x   7 wnagzihxa1n  staff         224 Jan  2 19:42 ..
-rw-r--r--1 wnagzihxa1n  staff  2874835794 Jan  9  2007 038-60223-004.dmg
-rw-r--r--1 wnagzihxa1n  staff    93846555 Jan  9  2007 038-60285-004.dmg
-rw-r--r--1 wnagzihxa1n  staff    91602971 Jan  9  2007 038-60305-004.dmg
-rw-r--r--1 wnagzihxa1n  staff      128367 Jan  9  2007 BuildManifest.plist
drwxr-xr-x@ 10 wnagzihxa1n  staff         320 Jan  9  2007 Firmware
-rw-r--r--1 wnagzihxa1n  staff         985 Jan  9  2007 Restore.plist
-rw-r--r--1 wnagzihxa1n  staff    14061377 Jan  9  2007 kernelcache.release.iphone7
➜  iPhone_4.7_12.4.8_16G201_Restore ls -al
total 6012560
drwxr-xr-x@  9 wnagzihxa1n  staff         288 Jan  2 19:41 .
drwxr-xr-x   7 wnagzihxa1n  staff         224 Jan  2 19:42 ..
-rw-r--r--1 wnagzihxa1n  staff  2874835794 Jan  9  2007 038-60223-004.dmg
-rw-r--r--1 wnagzihxa1n  staff    93846555 Jan  9  2007 038-60285-004.dmg
-rw-r--r--1 wnagzihxa1n  staff    91602971 Jan  9  2007 038-60305-004.dmg
-rw-r--r--1 wnagzihxa1n  staff      128367 Jan  9  2007 BuildManifest.plist
drwxr-xr-x@ 10 wnagzihxa1n  staff         320 Jan  9  2007 Firmware
-rw-r--r--1 wnagzihxa1n  staff         985 Jan  9  2007 Restore.plist
-rw-r--r--1 wnagzihxa1n  staff    14061377 Jan  9  2007 kernelcache.release.iphone7
➜  iPhone_4.7_12.4.8_16G201_Restore xxd -a kernelcache.release.iphone7 | head -n 10
00000000: 3083 d68f 3c16 0449 4d34 5016 046b 726e  0...<..IM4P..krn
00000010: 6c16 1e4b 6572 6e65 6c43 6163 6865 4275  l..KernelCacheBu
00000020: 696c 6465 722d 3134 3639 2e32 3630 2e31  ilder-1469.260.1
00000030: 3504 83d6 8f0b 636f 6d70 6c7a 7373 025a  5.....complzss.Z
00000040: b99c 01ae f208 00d5 cd8b 0000 0001 0000  ................
00000050: 0000 0000 0000 0000 0000 0000 0000 0000  ................
*
000001b0: 0000 0000 0000 ffcf faed fe0c 0000 01d5  ................
000001c0: 00f6 f002 f6f0 16f6 f058 115a f3f1 20f6  .........X.Z.. .
000001d0: f100 19f6 f028 faf0 3f5f 5f54 4558 5409  .....(..?__TEXT.
➜  iPhone_4.7_12.4.8_16G201_Restore xxd -a kernelcache.release.iphone7 | head -n 10
00000000: 3083 d68f 3c16 0449 4d34 5016 046b 726e  0...<..IM4P..krn
00000010: 6c16 1e4b 6572 6e65 6c43 6163 6865 4275  l..KernelCacheBu
00000020: 696c 6465 722d 3134 3639 2e32 3630 2e31  ilder-1469.260.1
00000030: 3504 83d6 8f0b 636f 6d70 6c7a 7373 025a  5.....complzss.Z
00000040: b99c 01ae f208 00d5 cd8b 0000 0001 0000  ................
00000050: 0000 0000 0000 0000 0000 0000 0000 0000  ................
*
000001b0: 0000 0000 0000 ffcf faed fe0c 0000 01d5  ................
000001c0: 00f6 f002 f6f0 16f6 f058 115a f3f1 20f6  .........X.Z.. .
000001d0: f100 19f6 f028 faf0 3f5f 5f54 4558 5409  .....(..?__TEXT.
➜  lzssdec wget http://nah6.com/\~itsme/cvs-xdadevtools/iphone/tools/lzssdec.cpp
➜  lzssdec g++ lzssdec.cpp -o lzssdec
➜  lzssdec wget http://nah6.com/\~itsme/cvs-xdadevtools/iphone/tools/lzssdec.cpp
➜  lzssdec g++ lzssdec.cpp -o lzssdec
➜  iPhone_4.7_12.4.8_16G201_Restore ./lzssdec -o 0x1b6 < kernelcache.release.iphone7 > kernelcache.release.iphone7.bin
➜  iPhone_4.7_12.4.8_16G201_Restore ./lzssdec -o 0x1b6 < kernelcache.release.iphone7 > kernelcache.release.iphone7.bin
➜  iPhone_4.7_12.4.8_16G201_Restore file kernelcache.release.iphone7.bin
kernelcache.release.iphone7.bin: Mach-O 64-bit executable arm64
➜  iPhone_4.7_12.4.9_16H5_Restore file kernelcache.release.iphone7.bin                                             
kernelcache.release.iphone7.bin: Mach-O 64-bit executable arm64
➜  iPhone_4.7_12.4.8_16G201_Restore file kernelcache.release.iphone7.bin
kernelcache.release.iphone7.bin: Mach-O 64-bit executable arm64
➜  iPhone_4.7_12.4.9_16H5_Restore file kernelcache.release.iphone7.bin                                             
kernelcache.release.iphone7.bin: Mach-O 64-bit executable arm64
 
 
➜  ~ sudo ln -s /Applications/BinDiff/BinDiff.app/Contents/MacOS/bin/bindiff /Applications/BinDiff/BinDiff.app/Contents/app/bindiff
➜  ~ sudo ln -s /Applications/BinDiff/BinDiff.app/Contents/MacOS/bin/bindiff /Applications/BinDiff/BinDiff.app/Contents/app/bindiff
 
 
 
 
__TEXT_EXEC:__text:FFFFFFF00768E4C4 MOV             W1, #0x44 ; 'D'
__TEXT_EXEC:__text:FFFFFFF00768E4C8 MOV             X0, X20
__TEXT_EXEC:__text:FFFFFFF00768E4CC BL              sub_FFFFFFF00766D6C0
__TEXT_EXEC:__text:FFFFFFF00768E4D0 MOV             W23, #0
__TEXT_EXEC:__text:FFFFFFF00768E4C4 MOV             W1, #0x44 ; 'D'
__TEXT_EXEC:__text:FFFFFFF00768E4C8 MOV             X0, X20
__TEXT_EXEC:__text:FFFFFFF00768E4CC BL              sub_FFFFFFF00766D6C0
__TEXT_EXEC:__text:FFFFFFF00768E4D0 MOV             W23, #0
 
 
 
 
 
 
bzero(trailer, sizeof(*trailer));
bzero(trailer, sizeof(*trailer));
 
 
typedef mach_msg_mac_trailer_t mach_msg_max_trailer_t;
mach_msg_max_trailer_t          *trailer;
typedef mach_msg_mac_trailer_t mach_msg_max_trailer_t;
mach_msg_max_trailer_t          *trailer;
#define MACH_MSG_TRAILER_MINIMUM_SIZE  sizeof(mach_msg_trailer_t)
#define MAX_TRAILER_SIZE ((mach_msg_size_t)sizeof(mach_msg_max_trailer_t))
 
typedef struct{
    mach_msg_trailer_type_t       msgh_trailer_type;
    mach_msg_trailer_size_t       msgh_trailer_size;
    mach_port_seqno_t             msgh_seqno;
    security_token_t              msgh_sender;
    audit_token_t                 msgh_audit;
    mach_port_context_t           msgh_context;
    mach_msg_filter_id            msgh_ad;
    msg_labels_t                  msgh_labels;
} mach_msg_mac_trailer_t;
 
typedef struct{
    mach_msg_trailer_type_t       msgh_trailer_type;
    mach_msg_trailer_size_t       msgh_trailer_size;
} mach_msg_trailer_t;
#define MACH_MSG_TRAILER_MINIMUM_SIZE  sizeof(mach_msg_trailer_t)
#define MAX_TRAILER_SIZE ((mach_msg_size_t)sizeof(mach_msg_max_trailer_t))
 
typedef struct{
    mach_msg_trailer_type_t       msgh_trailer_type;
    mach_msg_trailer_size_t       msgh_trailer_size;
    mach_port_seqno_t             msgh_seqno;
    security_token_t              msgh_sender;
    audit_token_t                 msgh_audit;
    mach_port_context_t           msgh_context;
    mach_msg_filter_id            msgh_ad;
    msg_labels_t                  msgh_labels;
} mach_msg_mac_trailer_t;
 
typedef struct{
    mach_msg_trailer_type_t       msgh_trailer_type;
    mach_msg_trailer_size_t       msgh_trailer_size;
} mach_msg_trailer_t;
 
 
 
 
 
 
 
 
extern mach_msg_return_t mach_msg(
        mach_msg_header_t       *msg,
        mach_msg_option_t       option,
        mach_msg_size_t         send_size,
        mach_msg_size_t         rcv_size,
        mach_port_name_t        rcv_name,
        mach_msg_timeout_t      timeout,
        mach_port_name_t        notify);
extern mach_msg_return_t mach_msg(
        mach_msg_header_t       *msg,
        mach_msg_option_t       option,
        mach_msg_size_t         send_size,
        mach_msg_size_t         rcv_size,
        mach_port_name_t        rcv_name,
        mach_msg_timeout_t      timeout,
        mach_port_name_t        notify);
typedef struct{
    mach_msg_header_t       header;
    mach_msg_body_t         body;
} mach_msg_base_t;
 
typedef struct{
    mach_msg_bits_t       msgh_bits;
    mach_msg_size_t       msgh_size;
    mach_port_t           msgh_remote_port;
    mach_port_t           msgh_local_port;
    mach_port_name_t      msgh_voucher_port;
    mach_msg_id_t         msgh_id;
} mach_msg_header_t;
 
typedef struct{
    mach_msg_size_t msgh_descriptor_count;
} mach_msg_body_t;
typedef struct{
    mach_msg_header_t       header;
    mach_msg_body_t         body;
} mach_msg_base_t;
 
typedef struct{
    mach_msg_bits_t       msgh_bits;
    mach_msg_size_t       msgh_size;
    mach_port_t           msgh_remote_port;
    mach_port_t           msgh_local_port;
    mach_port_name_t      msgh_voucher_port;
    mach_msg_id_t         msgh_id;
} mach_msg_header_t;
 
typedef struct{
    mach_msg_size_t msgh_descriptor_count;
} mach_msg_body_t;
 
 
mach_port_t port;
mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port);
mach_port_t port;
mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port);
mach_port_insert_right(mach_task_self(), port, port, MACH_MSG_TYPE_MAKE_SEND);
mach_port_insert_right(mach_task_self(), port, port, MACH_MSG_TYPE_MAKE_SEND);
bootstrap_register(bootstrap_port, "com.wnagzihxa1n.port", port);
bootstrap_register(bootstrap_port, "com.wnagzihxa1n.port", port);
struct {
    mach_msg_header_t header;
    char some_text[10];
    int some_number;
    mach_msg_trailer_t trailer;
} message;
 
kr = mach_msg(
    &message.header,  // 另一种写法 (mach_msg_header_t *) &message.
    MACH_RCV_MSG,     // 两种选项:发送和接收,此处是接收
    0,                // 发送消息的长度
    sizeof(message),  // 等待接收消息的长度
    port,             // 要获取消息的port
    MACH_MSG_TIMEOUT_NONE,
    MACH_PORT_NULL);
struct {
    mach_msg_header_t header;
    char some_text[10];
    int some_number;
    mach_msg_trailer_t trailer;
} message;
 
kr = mach_msg(
    &message.header,  // 另一种写法 (mach_msg_header_t *) &message.
    MACH_RCV_MSG,     // 两种选项:发送和接收,此处是接收
    0,                // 发送消息的长度
    sizeof(message),  // 等待接收消息的长度
    port,             // 要获取消息的port
    MACH_MSG_TIMEOUT_NONE,
    MACH_PORT_NULL);
typedef struct{
    mach_msg_trailer_type_t       msgh_trailer_type;
    mach_msg_trailer_size_t       msgh_trailer_size;
} mach_msg_trailer_t;
typedef struct{
    mach_msg_trailer_type_t       msgh_trailer_type;
    mach_msg_trailer_size_t       msgh_trailer_size;
} mach_msg_trailer_t;
 
mach_port_t port;
bootstrap_look_up(bootstrap_port, "com.wnagzihxa1n.port", &port);
mach_port_t port;
bootstrap_look_up(bootstrap_port, "com.wnagzihxa1n.port", &port);
struct {
    mach_msg_header_t header;
    char some_text[10];
    int some_number;
} message;
 
message.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
message.header.msgh_remote_port = port;
message.header.msgh_local_port = MACH_PORT_NULL;
 
strncpy(message.some_text, "Hello", sizeof(message.some_text));
message.some_number = 1337;
struct {
    mach_msg_header_t header;
    char some_text[10];
    int some_number;
} message;
 
message.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
message.header.msgh_remote_port = port;
message.header.msgh_local_port = MACH_PORT_NULL;
 
strncpy(message.some_text, "Hello", sizeof(message.some_text));
message.some_number = 1337;
kr = mach_msg(
    &message.header,  // 另一种写法 (mach_msg_header_t *) &message.
    MACH_SEND_MSG,    // 两种选项:发送和接收,此处是发送
    sizeof(message),  // 发送消息的长度
    0,                // 等待接收消息的长度
    MACH_PORT_NULL,   // 要获取消息的port
    MACH_MSG_TIMEOUT_NONE,
    MACH_PORT_NULL);
kr = mach_msg(
    &message.header,  // 另一种写法 (mach_msg_header_t *) &message.
    MACH_SEND_MSG,    // 两种选项:发送和接收,此处是发送
    sizeof(message),  // 发送消息的长度
    0,                // 等待接收消息的长度
    MACH_PORT_NULL,   // 要获取消息的port
    MACH_MSG_TIMEOUT_NONE,
    MACH_PORT_NULL);
 
struct {
    mach_msg_header_t header;
    char some_text[10];
    int some_number;
    mach_msg_security_trailer_t trailer;
} message;
 
kr = mach_msg(
    &message.header,  // 另一种写法 (mach_msg_header_t *) &message.
    MACH_RCV_MSG | MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_SENDER),     // <-- 添加trailer请求位
    0,                // 发送消息的长度
    sizeof(message),  // 等待接收消息的长度
    port,             // 要获取消息的port
    MACH_MSG_TIMEOUT_NONE,
    MACH_PORT_NULL);
struct {
    mach_msg_header_t header;
    char some_text[10];
    int some_number;
    mach_msg_security_trailer_t trailer;
} message;
 
kr = mach_msg(
    &message.header,  // 另一种写法 (mach_msg_header_t *) &message.
    MACH_RCV_MSG | MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_SENDER),     // <-- 添加trailer请求位
    0,                // 发送消息的长度
    sizeof(message),  // 等待接收消息的长度
    port,             // 要获取消息的port
    MACH_MSG_TIMEOUT_NONE,
    MACH_PORT_NULL);
printf("Sender's user id is %u\nSender's user group is %u\n",
       message.trailer.msgh_sender.val[0],
       message.trailer.msgh_sender.val[1]);
 
// Sender's user id is 501
// Sender's user group is 20
// ➜  id
// uid=501(wnagzihxa1n) gid=20(staff) groups=20(staff)
printf("Sender's user id is %u\nSender's user group is %u\n",
       message.trailer.msgh_sender.val[0],
       message.trailer.msgh_sender.val[1]);
 
// Sender's user id is 501
// Sender's user group is 20
// ➜  id
// uid=501(wnagzihxa1n) gid=20(staff) groups=20(staff)
 
 
/* The options that the kernel honors when passed from user space */
#define MACH_SEND_USER (
    MACH_SEND_MSG |
    MACH_SEND_TIMEOUT |
    MACH_SEND_NOTIFY |
    MACH_SEND_OVERRIDE |
    MACH_SEND_TRAILER |
    MACH_SEND_NOIMPORTANCE |
    MACH_SEND_SYNC_OVERRIDE |
    MACH_SEND_PROPAGATE_QOS |
    MACH_SEND_SYNC_BOOTSTRAP_CHECKIN |
    MACH_MSG_STRICT_REPLY |
    MACH_RCV_GUARDED_DESC)
 
#define MACH_RCV_USER (
    MACH_RCV_MSG |
    MACH_RCV_TIMEOUT |
    MACH_RCV_LARGE |
    MACH_RCV_LARGE_IDENTITY |
    MACH_RCV_VOUCHER |
    MACH_RCV_TRAILER_MASK |
    MACH_RCV_SYNC_WAIT |
    MACH_RCV_SYNC_PEEK  |
    MACH_RCV_GUARDED_DESC |
    MACH_MSG_STRICT_REPLY)
/* The options that the kernel honors when passed from user space */
#define MACH_SEND_USER (
    MACH_SEND_MSG |
    MACH_SEND_TIMEOUT |
    MACH_SEND_NOTIFY |
    MACH_SEND_OVERRIDE |
    MACH_SEND_TRAILER |
    MACH_SEND_NOIMPORTANCE |
    MACH_SEND_SYNC_OVERRIDE |
    MACH_SEND_PROPAGATE_QOS |
    MACH_SEND_SYNC_BOOTSTRAP_CHECKIN |
    MACH_MSG_STRICT_REPLY |
    MACH_RCV_GUARDED_DESC)
 
#define MACH_RCV_USER (
    MACH_RCV_MSG |
    MACH_RCV_TIMEOUT |
    MACH_RCV_LARGE |
    MACH_RCV_LARGE_IDENTITY |
    MACH_RCV_VOUCHER |
    MACH_RCV_TRAILER_MASK |
    MACH_RCV_SYNC_WAIT |
    MACH_RCV_SYNC_PEEK  |
    MACH_RCV_GUARDED_DESC |
    MACH_MSG_STRICT_REPLY)
 
 
mach_msg_return_t
mach_msg_trap(
    struct mach_msg_overwrite_trap_args *args)
{
    kern_return_t kr;
    args->rcv_msg = (mach_vm_address_t)0;
 
    kr = mach_msg_overwrite_trap(args);
    return kr;
}
mach_msg_return_t
mach_msg_trap(
    struct mach_msg_overwrite_trap_args *args)
{
    kern_return_t kr;
    args->rcv_msg = (mach_vm_address_t)0;
 
    kr = mach_msg_overwrite_trap(args);
    return kr;
}
 
mach_msg_return_t
mach_msg_overwrite_trap(
    struct mach_msg_overwrite_trap_args *args)
{
    mach_vm_address_t       msg_addr = args->msg;
    mach_msg_option_t       option = args->option;  // mach_msg()第二个参数
    ...
 
    mach_msg_return_t  mr = MACH_MSG_SUCCESS; // 大吉大利
    vm_map_t map = current_map();
 
    /* Only accept options allowed by the user */
    option &= MACH_MSG_OPTION_USER;
 
    if (option & MACH_SEND_MSG) {
        ipc_space_t space = current_space();
        ipc_kmsg_t kmsg;    // 创建kmsg变量
 
        // 分配缓冲区并从用户态拷贝数据到内核态
        mr = ipc_kmsg_get(msg_addr, send_size, &kmsg);
        // 转换端口,从用户态转换为内核态地址
        mr = ipc_kmsg_copyin(kmsg, space, map, override, &option);
        // 发送消息
        mr = ipc_kmsg_send(kmsg, option, msg_timeout);
    }
 
    if (option & MACH_RCV_MSG) {
        ...
    }
 
    return MACH_MSG_SUCCESS;
}
mach_msg_return_t
mach_msg_overwrite_trap(
    struct mach_msg_overwrite_trap_args *args)
{
    mach_vm_address_t       msg_addr = args->msg;
    mach_msg_option_t       option = args->option;  // mach_msg()第二个参数
    ...
 
    mach_msg_return_t  mr = MACH_MSG_SUCCESS; // 大吉大利
    vm_map_t map = current_map();
 
    /* Only accept options allowed by the user */
    option &= MACH_MSG_OPTION_USER;
 
    if (option & MACH_SEND_MSG) {
        ipc_space_t space = current_space();
        ipc_kmsg_t kmsg;    // 创建kmsg变量
 
        // 分配缓冲区并从用户态拷贝数据到内核态
        mr = ipc_kmsg_get(msg_addr, send_size, &kmsg);
        // 转换端口,从用户态转换为内核态地址
        mr = ipc_kmsg_copyin(kmsg, space, map, override, &option);
        // 发送消息
        mr = ipc_kmsg_send(kmsg, option, msg_timeout);
    }
 
    if (option & MACH_RCV_MSG) {
        ...
    }
 
    return MACH_MSG_SUCCESS;
}
mach_msg_return_t
ipc_kmsg_get(
    mach_vm_address_t       msg_addr,
    mach_msg_size_t size,
    ipc_kmsg_t              *kmsgp)
{
    mach_msg_size_t                 msg_and_trailer_size;
    ipc_kmsg_t                      kmsg;
    mach_msg_max_trailer_t          *trailer;
    mach_msg_legacy_base_t      legacy_base;
    mach_msg_size_t             len_copied;
    legacy_base.body.msgh_descriptor_count = 0;
 
    // 长度参数检查
 
    // mach_msg_legacy_base_t结构体长度等于mach_msg_base_t
    if (size == sizeof(mach_msg_legacy_header_t)) {
        len_copied = sizeof(mach_msg_legacy_header_t);
    } else {
        len_copied = sizeof(mach_msg_legacy_base_t);
    }
 
    // 从用户态拷贝消息到内核态
    if (copyinmsg(msg_addr, (char *)&legacy_base, len_copied)) {
        return MACH_SEND_INVALID_DATA;
    }
 
    // 获取内核态消息变量起始地址
    msg_addr += sizeof(legacy_base.header);
 
    // 直接加上最长的trailer长度,不知道接收者会定义何种类型的trailer,此处是做备用操作
    // typedef mach_msg_mac_trailer_t mach_msg_max_trailer_t;
    // #define MAX_TRAILER_SIZE ((mach_msg_size_t)sizeof(mach_msg_max_trailer_t))
    msg_and_trailer_size = size + MAX_TRAILER_SIZE;
 
    // 分配内核空间
    kmsg = ipc_kmsg_alloc(msg_and_trailer_size);
 
    // 初始化kmsg.ikm_header部分字段
 
    // 拷贝消息体,此处不包括trailer
    if (copyinmsg(msg_addr, (char *)(kmsg->ikm_header + 1), size - (mach_msg_size_t)sizeof(mach_msg_header_t))) {
        ipc_kmsg_free(kmsg);
        return MACH_SEND_INVALID_DATA;
    }
 
    // 通过size找到kmsg尾部trailer的起始地址,进行初始化
    // 注意它的msgh_trailer_size是最小的MACH_MSG_TRAILER_MINIMUM_SIZE
    trailer = (mach_msg_max_trailer_t *) ((vm_offset_t)kmsg->ikm_header + size);
    trailer->msgh_sender = current_thread()->task->sec_token;
    trailer->msgh_audit = current_thread()->task->audit_token;
    trailer->msgh_trailer_type = MACH_MSG_TRAILER_FORMAT_0;
    trailer->msgh_trailer_size = MACH_MSG_TRAILER_MINIMUM_SIZE;
    trailer->msgh_labels.sender = 0;
 
    *kmsgp = kmsg;
    return MACH_MSG_SUCCESS;
}
mach_msg_return_t
ipc_kmsg_get(
    mach_vm_address_t       msg_addr,
    mach_msg_size_t size,
    ipc_kmsg_t              *kmsgp)
{
    mach_msg_size_t                 msg_and_trailer_size;
    ipc_kmsg_t                      kmsg;
    mach_msg_max_trailer_t          *trailer;
    mach_msg_legacy_base_t      legacy_base;
    mach_msg_size_t             len_copied;
    legacy_base.body.msgh_descriptor_count = 0;
 
    // 长度参数检查
 
    // mach_msg_legacy_base_t结构体长度等于mach_msg_base_t
    if (size == sizeof(mach_msg_legacy_header_t)) {
        len_copied = sizeof(mach_msg_legacy_header_t);
    } else {
        len_copied = sizeof(mach_msg_legacy_base_t);
    }
 
    // 从用户态拷贝消息到内核态
    if (copyinmsg(msg_addr, (char *)&legacy_base, len_copied)) {
        return MACH_SEND_INVALID_DATA;
    }
 
    // 获取内核态消息变量起始地址
    msg_addr += sizeof(legacy_base.header);
 
    // 直接加上最长的trailer长度,不知道接收者会定义何种类型的trailer,此处是做备用操作
    // typedef mach_msg_mac_trailer_t mach_msg_max_trailer_t;
    // #define MAX_TRAILER_SIZE ((mach_msg_size_t)sizeof(mach_msg_max_trailer_t))
    msg_and_trailer_size = size + MAX_TRAILER_SIZE;
 
    // 分配内核空间
    kmsg = ipc_kmsg_alloc(msg_and_trailer_size);
 
    // 初始化kmsg.ikm_header部分字段
 
    // 拷贝消息体,此处不包括trailer
    if (copyinmsg(msg_addr, (char *)(kmsg->ikm_header + 1), size - (mach_msg_size_t)sizeof(mach_msg_header_t))) {
        ipc_kmsg_free(kmsg);
        return MACH_SEND_INVALID_DATA;
    }
 
    // 通过size找到kmsg尾部trailer的起始地址,进行初始化
    // 注意它的msgh_trailer_size是最小的MACH_MSG_TRAILER_MINIMUM_SIZE
    trailer = (mach_msg_max_trailer_t *) ((vm_offset_t)kmsg->ikm_header + size);
    trailer->msgh_sender = current_thread()->task->sec_token;
    trailer->msgh_audit = current_thread()->task->audit_token;
    trailer->msgh_trailer_type = MACH_MSG_TRAILER_FORMAT_0;
    trailer->msgh_trailer_size = MACH_MSG_TRAILER_MINIMUM_SIZE;
    trailer->msgh_labels.sender = 0;
 
    *kmsgp = kmsg;
    return MACH_MSG_SUCCESS;
}
trailer->msgh_sender = current_thread()->task->sec_token;
trailer->msgh_audit = current_thread()->task->audit_token;
trailer->msgh_labels.sender = 0;
 
typedef struct{
    mach_msg_trailer_type_t       msgh_trailer_type;
    mach_msg_trailer_size_t       msgh_trailer_size;
    mach_port_seqno_t             msgh_seqno;
    security_token_t              msgh_sender;
    audit_token_t                 msgh_audit;
    mach_port_context_t           msgh_context;
    mach_msg_filter_id            msgh_ad;
    msg_labels_t                  msgh_labels;
} mach_msg_mac_trailer_t;
trailer->msgh_sender = current_thread()->task->sec_token;

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 5
支持
分享
最新回复 (1)
雪    币: 29177
活跃值: (63586)
能力值: (RANK:135 )
在线值:
发帖
回帖
粉丝
2
感谢分享!
2021-2-3 15:57
0
游客
登录 | 注册 方可回帖
返回
//