1 /*
2 * Copyright (c) 2014 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29
30 #include <libkern/c++/OSSharedPtr.h>
31 #include <libkern/OSSerializeBinary.h>
32 #include <libkern/c++/OSContainers.h>
33 #include <libkern/c++/OSLib.h>
34 #include <libkern/c++/OSDictionary.h>
35 #include <libkern/OSSerializeBinary.h>
36 #include <libkern/c++/OSSharedPtr.h>
37
38 #include <IOKit/IOLib.h>
39
40 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
41
42 #if 0
43 #define DEBG(fmt, args ...) { kprintf(fmt, args); }
44 #else
45 #define DEBG(fmt, args ...) {}
46 #endif
47
48 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
49
50 OSSerialize *
binaryWithCapacity(unsigned int inCapacity,Editor editor,void * reference)51 OSSerialize::binaryWithCapacity(unsigned int inCapacity,
52 Editor editor, void * reference)
53 {
54 OSSerialize *me;
55
56 if (inCapacity < sizeof(uint32_t)) {
57 return NULL;
58 }
59 me = OSSerialize::withCapacity(inCapacity);
60 if (!me) {
61 return NULL;
62 }
63
64 me->binary = true;
65 me->endCollection = true;
66 me->editor = editor;
67 me->editRef = reference;
68
69 bcopy(kOSSerializeBinarySignature, &me->data[0], sizeof(kOSSerializeBinarySignature));
70 me->length = sizeof(kOSSerializeBinarySignature);
71
72 return me;
73 }
74
75 bool
addBinary(const void * bits,size_t size)76 OSSerialize::addBinary(const void * bits, size_t size)
77 {
78 unsigned int newCapacity;
79 size_t alignSize;
80
81 if (os_add_overflow(size, 3, &alignSize)) {
82 return false;
83 }
84 alignSize &= ~3L;
85 if (os_add_overflow(length, alignSize, &newCapacity)) {
86 return false;
87 }
88 if (newCapacity >= capacity) {
89 newCapacity = (((newCapacity - 1) / capacityIncrement) + 1) * capacityIncrement;
90 if (newCapacity < capacity) {
91 return false;
92 }
93 if (newCapacity > ensureCapacity(newCapacity)) {
94 return false;
95 }
96 }
97
98 bcopy(bits, &data[length], size);
99 length += alignSize;
100
101 return true;
102 }
103
104 void
setIndexed(bool index __unused)105 OSSerialize::setIndexed(bool index __unused)
106 {
107 assert(index && !indexData);
108 indexData = OSData::withCapacity(256);
109 assert(indexData);
110 }
111
112 bool
addBinaryObject(const OSMetaClassBase * o,uint32_t key,const void * bits,uint32_t size,uint32_t * startCollection)113 OSSerialize::addBinaryObject(const OSMetaClassBase * o, uint32_t key,
114 const void * bits, uint32_t size,
115 uint32_t * startCollection)
116 {
117 unsigned int newCapacity;
118 size_t alignSize;
119 size_t headerSize;
120
121 // add to tag array
122 tags->setObject(o);
123
124 headerSize = sizeof(key);
125 if (indexData) {
126 uint32_t offset = length;
127 if (startCollection) {
128 *startCollection = offset;
129 headerSize += sizeof(uint32_t);
130 }
131 offset /= sizeof(uint32_t);
132 indexData->appendBytes(&offset, sizeof(offset));
133 }
134
135 if (os_add3_overflow(size, headerSize, 3, &alignSize)) {
136 return false;
137 }
138 alignSize &= ~3L;
139 if (os_add_overflow(length, alignSize, &newCapacity)) {
140 return false;
141 }
142 if (newCapacity >= capacity) {
143 newCapacity = (((newCapacity - 1) / capacityIncrement) + 1) * capacityIncrement;
144 if (newCapacity < capacity) {
145 return false;
146 }
147 if (newCapacity > ensureCapacity(newCapacity)) {
148 return false;
149 }
150 }
151
152 if (endCollection) {
153 endCollection = false;
154 key |= kOSSerializeEndCollecton;
155 }
156
157 bcopy(&key, &data[length], sizeof(key));
158 bcopy(bits, &data[length + headerSize], size);
159 length += alignSize;
160
161 return true;
162 }
163
164 void
endBinaryCollection(uint32_t startCollection)165 OSSerialize::endBinaryCollection(uint32_t startCollection)
166 {
167 uint32_t clength;
168
169 if (!indexData) {
170 return;
171 }
172
173 assert(length > startCollection);
174 if (length <= startCollection) {
175 return;
176 }
177
178 clength = length - startCollection;
179 assert(!(clength & 3));
180 clength /= sizeof(uint32_t);
181
182 memcpy(&data[startCollection + sizeof(uint32_t)], &clength, sizeof(clength));
183 }
184
185 bool
binarySerialize(const OSMetaClassBase * o)186 OSSerialize::binarySerialize(const OSMetaClassBase *o)
187 {
188 bool ok;
189 uint32_t header;
190
191 ok = binarySerializeInternal(o);
192 if (!ok) {
193 return ok;
194 }
195
196 if (indexData) {
197 header = indexData->getLength() / sizeof(uint32_t);
198 assert(header <= kOSSerializeDataMask);
199 header <<= 8;
200 header |= kOSSerializeIndexedBinarySignature;
201
202 memcpy(&data[0], &header, sizeof(header));
203 }
204
205 return ok;
206 }
207
208 bool
binarySerializeInternal(const OSMetaClassBase * o)209 OSSerialize::binarySerializeInternal(const OSMetaClassBase *o)
210 {
211 OSDictionary * dict;
212 OSArray * array;
213 OSSet * set;
214 OSNumber * num;
215 OSSymbol * sym;
216 OSString * str;
217 OSData * ldata;
218 OSBoolean * boo;
219
220 unsigned int tagIdx;
221 uint32_t i, key, startCollection;
222 uint32_t len;
223 bool ok;
224
225 tagIdx = tags->getNextIndexOfObject(o, 0);
226 // does it exist?
227 if (-1U != tagIdx) {
228 if (indexData) {
229 assert(indexData->getLength() > (tagIdx * sizeof(uint32_t)));
230 tagIdx = ((const uint32_t *)indexData->getBytesNoCopy())[tagIdx];
231 assert(tagIdx <= kOSSerializeDataMask);
232 }
233 key = (kOSSerializeObject | tagIdx);
234 if (endCollection) {
235 endCollection = false;
236 key |= kOSSerializeEndCollecton;
237 }
238 ok = addBinary(&key, sizeof(key));
239 return ok;
240 }
241
242 if ((dict = OSDynamicCast(OSDictionary, o))) {
243 key = (kOSSerializeDictionary | dict->count);
244 ok = addBinaryObject(o, key, NULL, 0, &startCollection);
245 for (i = 0; ok && (i < dict->count);) {
246 const OSSymbol * dictKey;
247 const OSMetaClassBase * dictValue;
248 const OSMetaClassBase * nvalue = NULL;
249
250 dictKey = dict->dictionary[i].key;
251 dictValue = dict->dictionary[i].value;
252 i++;
253 if (editor) {
254 dictValue = nvalue = (*editor)(editRef, this, dict, dictKey, dictValue);
255 if (!dictValue) {
256 dictValue = dict;
257 }
258 }
259 ok = binarySerialize(dictKey);
260 if (!ok) {
261 break;
262 }
263 endCollection = (i == dict->count);
264 ok = binarySerialize(dictValue);
265 if (!ok) {
266 ok = dictValue->serialize(this);
267 }
268 if (nvalue) {
269 nvalue->release();
270 }
271 // if (!ok) ok = binarySerialize(kOSBooleanFalse);
272 }
273 endBinaryCollection(startCollection);
274 } else if ((array = OSDynamicCast(OSArray, o))) {
275 key = (kOSSerializeArray | array->count);
276 ok = addBinaryObject(o, key, NULL, 0, &startCollection);
277 for (i = 0; ok && (i < array->count);) {
278 i++;
279 endCollection = (i == array->count);
280 ok = binarySerialize(array->array[i - 1]);
281 if (!ok) {
282 ok = array->array[i - 1]->serialize(this);
283 }
284 // if (!ok) ok = binarySerialize(kOSBooleanFalse);
285 }
286 endBinaryCollection(startCollection);
287 } else if ((set = OSDynamicCast(OSSet, o))) {
288 key = (kOSSerializeSet | set->members->count);
289 ok = addBinaryObject(o, key, NULL, 0, &startCollection);
290 for (i = 0; ok && (i < set->members->count);) {
291 i++;
292 endCollection = (i == set->members->count);
293 ok = binarySerialize(set->members->array[i - 1]);
294 if (!ok) {
295 ok = set->members->array[i - 1]->serialize(this);
296 }
297 // if (!ok) ok = binarySerialize(kOSBooleanFalse);
298 }
299 endBinaryCollection(startCollection);
300 } else if ((num = OSDynamicCast(OSNumber, o))) {
301 key = (kOSSerializeNumber | num->size);
302 ok = addBinaryObject(o, key, &num->value, sizeof(num->value), NULL);
303 } else if ((boo = OSDynamicCast(OSBoolean, o))) {
304 key = (kOSSerializeBoolean | (kOSBooleanTrue == boo));
305 ok = addBinaryObject(o, key, NULL, 0, NULL);
306 } else if ((sym = OSDynamicCast(OSSymbol, o))) {
307 len = (sym->getLength() + 1);
308 key = (kOSSerializeSymbol | len);
309 ok = addBinaryObject(o, key, sym->getCStringNoCopy(), len, NULL);
310 } else if ((str = OSDynamicCast(OSString, o))) {
311 len = str->getLength();
312 key = (kOSSerializeString | len);
313 ok = addBinaryObject(o, key, str->getCStringNoCopy(), len, NULL);
314 } else if ((ldata = OSDynamicCast(OSData, o))) {
315 len = ldata->getLength();
316 if (ldata->reserved && ldata->reserved->disableSerialization) {
317 len = 0;
318 }
319 key = (kOSSerializeData | len);
320 ok = addBinaryObject(o, key, ldata->getBytesNoCopy(), len, NULL);
321 } else {
322 return false;
323 }
324
325 return ok;
326 }
327
328 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
329
330 #define setAtIndex(v, idx, o) \
331 if (idx >= v##Capacity) \
332 { \
333 if (v##Capacity >= v##CapacityMax) ok = false; \
334 else \
335 { \
336 uint32_t ncap = v##Capacity + 64; \
337 typeof(v##Array) nbuf = kalloc_type_tag_bt(OSObject *, ncap, \
338 Z_WAITOK_ZERO, VM_KERN_MEMORY_LIBKERN); \
339 if (!nbuf) ok = false; \
340 else \
341 { \
342 if (v##Array) \
343 { \
344 bcopy(v##Array, nbuf, v##Capacity * sizeof(o)); \
345 kfree_type(OSObject *, v##Capacity, v##Array); \
346 } \
347 v##Array = nbuf; \
348 v##Capacity = ncap; \
349 } \
350 } \
351 } \
352 if (ok) v##Array[idx] = o
353
354 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
355
356 OSObject *
OSUnserializeBinary(const char * buffer,size_t bufferSize,OSString ** errorString)357 OSUnserializeBinary(const char *buffer, size_t bufferSize, OSString **errorString)
358 {
359 OSObject ** objsArray;
360 uint32_t objsCapacity;
361 enum { objsCapacityMax = 16 * 1024 * 1024 };
362 uint32_t objsIdx;
363
364 OSObject ** stackArray;
365 uint32_t stackCapacity;
366 enum { stackCapacityMax = 64 };
367 uint32_t stackIdx;
368
369 OSObject * result;
370 OSObject * parent;
371 OSDictionary * dict;
372 OSArray * array;
373 OSSet * set;
374 OSDictionary * newDict;
375 OSArray * newArray;
376 OSSet * newSet;
377 OSObject * o;
378 OSSymbol * sym;
379 OSString * str;
380
381 size_t bufferPos;
382 const uint32_t * next;
383 uint32_t key, len, wordLen, length;
384 bool end, newCollect, isRef;
385 unsigned long long value;
386 bool ok, indexed, hasLength;
387
388 indexed = false;
389 if (errorString) {
390 *errorString = NULL;
391 }
392
393 if (bufferSize < sizeof(kOSSerializeBinarySignature)) {
394 return NULL;
395 }
396 if (kOSSerializeIndexedBinarySignature == (((const uint8_t *) buffer)[0])) {
397 indexed = true;
398 } else if (0 != strcmp(kOSSerializeBinarySignature, buffer)) {
399 return NULL;
400 }
401 if (3 & ((uintptr_t) buffer)) {
402 return NULL;
403 }
404
405 bufferPos = sizeof(kOSSerializeBinarySignature);
406 next = (typeof(next))(((uintptr_t) buffer) + bufferPos);
407
408 DEBG("---------OSUnserializeBinary(%p)\n", buffer);
409
410 objsArray = stackArray = NULL;
411 objsIdx = objsCapacity = 0;
412 stackIdx = stackCapacity = 0;
413
414 result = NULL;
415 parent = NULL;
416 dict = NULL;
417 array = NULL;
418 set = NULL;
419 sym = NULL;
420
421 ok = true;
422 while (ok) {
423 bufferPos += sizeof(*next);
424 if (!(ok = (bufferPos <= bufferSize))) {
425 break;
426 }
427 key = *next++;
428 length = 0;
429
430 len = (key & kOSSerializeDataMask);
431 wordLen = (len + 3) >> 2;
432 end = (0 != (kOSSerializeEndCollecton & key));
433 DEBG("key 0x%08x: 0x%04x, %d\n", key, len, end);
434
435 newCollect = isRef = hasLength = false;
436 o = NULL; newDict = NULL; newArray = NULL; newSet = NULL;
437
438 switch (kOSSerializeTypeMask & key) {
439 case kOSSerializeDictionary:
440 o = newDict = OSDictionary::withCapacity(len);
441 newCollect = (len != 0);
442 hasLength = indexed;
443 break;
444 case kOSSerializeArray:
445 o = newArray = OSArray::withCapacity(len);
446 newCollect = (len != 0);
447 hasLength = indexed;
448 break;
449 case kOSSerializeSet:
450 o = newSet = OSSet::withCapacity(len);
451 newCollect = (len != 0);
452 hasLength = indexed;
453 break;
454
455 case kOSSerializeObject:
456 if (len >= objsIdx) {
457 break;
458 }
459 o = objsArray[len];
460 isRef = true;
461 break;
462
463 case kOSSerializeNumber:
464 bufferPos += sizeof(long long);
465 if (bufferPos > bufferSize) {
466 break;
467 }
468 if ((len != 32) && (len != 64) && (len != 16) && (len != 8)) {
469 break;
470 }
471 value = next[1];
472 value <<= 32;
473 value |= next[0];
474 o = OSNumber::withNumber(value, len);
475 next += 2;
476 break;
477
478 case kOSSerializeSymbol:
479 bufferPos += (wordLen * sizeof(uint32_t));
480 if (bufferPos > bufferSize) {
481 break;
482 }
483 if (len < 1) {
484 break;
485 }
486 if (0 != ((const char *)next)[len - 1]) {
487 break;
488 }
489 o = (OSObject *) OSSymbol::withCString((const char *) next);
490 next += wordLen;
491 break;
492
493 case kOSSerializeString:
494 bufferPos += (wordLen * sizeof(uint32_t));
495 if (bufferPos > bufferSize) {
496 break;
497 }
498 o = OSString::withCString((const char *) next, len);
499 next += wordLen;
500 break;
501
502 case kOSSerializeData:
503 bufferPos += (wordLen * sizeof(uint32_t));
504 if (bufferPos > bufferSize) {
505 break;
506 }
507 o = OSData::withBytes(next, len);
508 next += wordLen;
509 break;
510
511 case kOSSerializeBoolean:
512 o = (len ? kOSBooleanTrue : kOSBooleanFalse);
513 break;
514
515 default:
516 break;
517 }
518
519 if (!(ok = (o != NULL))) {
520 break;
521 }
522
523 if (hasLength) {
524 bufferPos += sizeof(*next);
525 if (!(ok = (bufferPos <= bufferSize))) {
526 o->release();
527 break;
528 }
529 length = *next++;
530 }
531
532 if (!isRef) {
533 setAtIndex(objs, objsIdx, o);
534 if (!ok) {
535 o->release();
536 break;
537 }
538 objsIdx++;
539 }
540
541 if (dict) {
542 if (!sym) {
543 sym = (OSSymbol *) o;
544 } else {
545 str = sym;
546 sym = OSDynamicCast(OSSymbol, sym);
547 if (!sym && (str = OSDynamicCast(OSString, str))) {
548 sym = const_cast<OSSymbol *>(OSSymbol::withString(str));
549 ok = (sym != NULL);
550 if (!ok) {
551 break;
552 }
553 }
554 DEBG("%s = %s\n", sym->getCStringNoCopy(), o->getMetaClass()->getClassName());
555 if (o != dict) {
556 ok = dict->setObject(sym, o);
557 }
558 if (sym && (sym != str)) {
559 sym->release();
560 }
561 sym = NULL;
562 }
563 } else if (array) {
564 ok = array->setObject(o);
565 } else if (set) {
566 ok = set->setObject(o);
567 } else if (result) {
568 ok = false;
569 } else {
570 assert(!parent);
571 result = o;
572 }
573
574 if (!ok) {
575 break;
576 }
577
578 if (end) {
579 parent = NULL;
580 }
581 if (newCollect) {
582 stackIdx++;
583 setAtIndex(stack, stackIdx, parent);
584 if (!ok) {
585 break;
586 }
587 DEBG("++stack[%d] %p\n", stackIdx, parent);
588 parent = o;
589 dict = newDict;
590 array = newArray;
591 set = newSet;
592 end = false;
593 }
594
595 if (end) {
596 while (stackIdx) {
597 parent = stackArray[stackIdx];
598 DEBG("--stack[%d] %p\n", stackIdx, parent);
599 stackIdx--;
600 if (parent) {
601 break;
602 }
603 }
604 if (!parent) {
605 break;
606 }
607 set = NULL;
608 dict = NULL;
609 array = NULL;
610 if (!(dict = OSDynamicCast(OSDictionary, parent))) {
611 if (!(array = OSDynamicCast(OSArray, parent))) {
612 ok = (NULL != (set = OSDynamicCast(OSSet, parent)));
613 }
614 }
615 }
616 }
617 DEBG("ret %p\n", result);
618
619 if (!ok) {
620 result = NULL;
621 }
622
623 if (objsCapacity) {
624 for (len = (result != NULL); len < objsIdx; len++) {
625 objsArray[len]->release();
626 }
627 kfree_type(OSObject *, objsCapacity, objsArray);
628 }
629 if (stackCapacity) {
630 kfree_type(OSObject *, stackCapacity, stackArray);
631 }
632
633 return result;
634 }
635
636 OSObject*
OSUnserializeXML(const char * buffer,OSSharedPtr<OSString> & errorString)637 OSUnserializeXML(
638 const char * buffer,
639 OSSharedPtr<OSString>& errorString)
640 {
641 OSString* errorStringRaw = NULL;
642 OSObject* result = OSUnserializeXML(buffer, &errorStringRaw);
643 errorString.reset(errorStringRaw, OSNoRetain);
644 return result;
645 }
646
647 OSObject*
OSUnserializeXML(const char * buffer,size_t bufferSize,OSSharedPtr<OSString> & errorString)648 OSUnserializeXML(
649 const char * buffer,
650 size_t bufferSize,
651 OSSharedPtr<OSString> &errorString)
652 {
653 OSString* errorStringRaw = NULL;
654 OSObject* result = OSUnserializeXML(buffer, bufferSize, &errorStringRaw);
655 errorString.reset(errorStringRaw, OSNoRetain);
656 return result;
657 }
658
659 OSObject*
OSUnserializeBinary(const char * buffer,size_t bufferSize,OSSharedPtr<OSString> & errorString)660 OSUnserializeBinary(const char *buffer, size_t bufferSize, OSSharedPtr<OSString>& errorString)
661 {
662 OSString* errorStringRaw = NULL;
663 OSObject* result = OSUnserializeBinary(buffer, bufferSize, &errorStringRaw);
664 errorString.reset(errorStringRaw, OSNoRetain);
665 return result;
666 }
667
668 OSObject*
OSUnserialize(const char * buffer,OSSharedPtr<OSString> & errorString)669 OSUnserialize(const char *buffer, OSSharedPtr<OSString>& errorString)
670 {
671 OSString* errorStringRaw = NULL;
672 OSObject* result = OSUnserialize(buffer, &errorStringRaw);
673 errorString.reset(errorStringRaw, OSNoRetain);
674 return result;
675 }
676