-
-
[原创]CVE-2020-27950 trailer->msgh_ad内核信息泄露
-
发表于: 2021-2-3 13:00 82376
-
公告
跟着这篇文章复现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.8
和kc_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_SIZE
,MAX_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 Message
和Complex Message
,作为复杂消息,自然包含的字段数据要比简单消息要多
Port简单可以理解为一个内核的消息队列,Task创建一个Port后,只有该Task对这个Port有接收消息的Right,其它Task都可以在获取发送Right后对该Port发送消息
Mach Message的接收与发送依赖函数mach_msg()
进行,这个函数在用户态与内核态均有实现
一条基本的消息由Message Header
和Message 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_MSG
和MACH_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,计算出的位数据为0b111000000000000000000000010
,MACH_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
,但是这里解析出错,因为4714839257292734464
是0x416e795300000000
,修正结构体偏移后,在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;