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 * 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 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 105 OSSerialize::setIndexed(bool index __unused) 106 { 107 assert(index && !indexData); 108 indexData = OSData::withCapacity(256); 109 assert(indexData); 110 } 111 112 bool 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->appendValue(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 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 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 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 = 0; 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 ok = idx < v##Capacity; \ 332 if (!ok && v##Capacity < v##CapacityMax) { \ 333 uint32_t ncap = v##Capacity + 64; \ 334 typeof(v##Array) nbuf = kreallocp_type_container(OSObject *, \ 335 v##Array, v##Capacity, &ncap, Z_WAITOK_ZERO); \ 336 if (nbuf) { \ 337 ok = true; \ 338 v##Array = nbuf; \ 339 v##Capacity = ncap; \ 340 } \ 341 } \ 342 if (ok) v##Array[idx] = o 343 344 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 345 346 OSObject * 347 OSUnserializeBinary(const char *buffer, size_t bufferSize, OSString **errorString) 348 { 349 OSObject ** objsArray; 350 uint32_t objsCapacity; 351 enum { objsCapacityMax = 16 * 1024 * 1024 }; 352 uint32_t objsIdx; 353 354 OSObject ** stackArray; 355 uint32_t stackCapacity; 356 enum { stackCapacityMax = 64 }; 357 uint32_t stackIdx; 358 359 OSObject * result; 360 OSObject * parent; 361 OSDictionary * dict; 362 OSArray * array; 363 OSSet * set; 364 OSDictionary * newDict; 365 OSArray * newArray; 366 OSSet * newSet; 367 OSObject * o; 368 OSSymbol * sym; 369 OSString * str; 370 371 size_t bufferPos; 372 const uint32_t * next; 373 uint32_t key, len, wordLen, length; 374 bool end, newCollect, isRef; 375 unsigned long long value; 376 bool ok, indexed, hasLength; 377 378 indexed = false; 379 if (errorString) { 380 *errorString = NULL; 381 } 382 383 if (bufferSize < sizeof(kOSSerializeBinarySignature)) { 384 return NULL; 385 } 386 if (kOSSerializeIndexedBinarySignature == (((const uint8_t *) buffer)[0])) { 387 indexed = true; 388 } else if (0 != strcmp(kOSSerializeBinarySignature, buffer)) { 389 return NULL; 390 } 391 if (3 & ((uintptr_t) buffer)) { 392 return NULL; 393 } 394 395 bufferPos = sizeof(kOSSerializeBinarySignature); 396 next = (typeof(next))(((uintptr_t) buffer) + bufferPos); 397 398 DEBG("---------OSUnserializeBinary(%p)\n", buffer); 399 400 objsArray = stackArray = NULL; 401 objsIdx = objsCapacity = 0; 402 stackIdx = stackCapacity = 0; 403 404 result = NULL; 405 parent = NULL; 406 dict = NULL; 407 array = NULL; 408 set = NULL; 409 sym = NULL; 410 411 ok = true; 412 while (ok) { 413 bufferPos += sizeof(*next); 414 if (!(ok = (bufferPos <= bufferSize))) { 415 break; 416 } 417 key = *next++; 418 length = 0; 419 420 len = (key & kOSSerializeDataMask); 421 wordLen = (len + 3) >> 2; 422 end = (0 != (kOSSerializeEndCollecton & key)); 423 DEBG("key 0x%08x: 0x%04x, %d\n", key, len, end); 424 425 newCollect = isRef = hasLength = false; 426 o = NULL; newDict = NULL; newArray = NULL; newSet = NULL; 427 428 switch (kOSSerializeTypeMask & key) { 429 case kOSSerializeDictionary: 430 o = newDict = OSDictionary::withCapacity(len); 431 newCollect = (len != 0); 432 hasLength = indexed; 433 break; 434 case kOSSerializeArray: 435 o = newArray = OSArray::withCapacity(len); 436 newCollect = (len != 0); 437 hasLength = indexed; 438 break; 439 case kOSSerializeSet: 440 o = newSet = OSSet::withCapacity(len); 441 newCollect = (len != 0); 442 hasLength = indexed; 443 break; 444 445 case kOSSerializeObject: 446 if (len >= objsIdx) { 447 break; 448 } 449 o = objsArray[len]; 450 isRef = true; 451 break; 452 453 case kOSSerializeNumber: 454 bufferPos += sizeof(long long); 455 if (bufferPos > bufferSize) { 456 break; 457 } 458 if ((len != 32) && (len != 64) && (len != 16) && (len != 8)) { 459 break; 460 } 461 value = next[1]; 462 value <<= 32; 463 value |= next[0]; 464 o = OSNumber::withNumber(value, len); 465 next += 2; 466 break; 467 468 case kOSSerializeSymbol: 469 bufferPos += (wordLen * sizeof(uint32_t)); 470 if (bufferPos > bufferSize) { 471 break; 472 } 473 if (len < 1) { 474 break; 475 } 476 if (0 != ((const char *)next)[len - 1]) { 477 break; 478 } 479 o = (OSObject *) OSSymbol::withCString((const char *) next); 480 next += wordLen; 481 break; 482 483 case kOSSerializeString: 484 bufferPos += (wordLen * sizeof(uint32_t)); 485 if (bufferPos > bufferSize) { 486 break; 487 } 488 o = OSString::withCString((const char *) next, len); 489 next += wordLen; 490 break; 491 492 case kOSSerializeData: 493 bufferPos += (wordLen * sizeof(uint32_t)); 494 if (bufferPos > bufferSize) { 495 break; 496 } 497 o = OSData::withBytes(next, len); 498 next += wordLen; 499 break; 500 501 case kOSSerializeBoolean: 502 o = (len ? kOSBooleanTrue : kOSBooleanFalse); 503 break; 504 505 default: 506 break; 507 } 508 509 if (!(ok = (o != NULL))) { 510 break; 511 } 512 513 if (hasLength) { 514 bufferPos += sizeof(*next); 515 if (!(ok = (bufferPos <= bufferSize))) { 516 o->release(); 517 break; 518 } 519 length = *next++; 520 } 521 522 if (!isRef) { 523 setAtIndex(objs, objsIdx, o); 524 if (!ok) { 525 o->release(); 526 break; 527 } 528 objsIdx++; 529 } 530 531 if (dict) { 532 if (!sym) { 533 sym = (OSSymbol *) o; 534 } else { 535 str = sym; 536 sym = OSDynamicCast(OSSymbol, sym); 537 if (!sym && (str = OSDynamicCast(OSString, str))) { 538 sym = const_cast<OSSymbol *>(OSSymbol::withString(str)); 539 ok = (sym != NULL); 540 if (!ok) { 541 break; 542 } 543 } 544 DEBG("%s = %s\n", sym->getCStringNoCopy(), o->getMetaClass()->getClassName()); 545 if (o != dict) { 546 ok = dict->setObject(sym, o); 547 } 548 if (sym && (sym != str)) { 549 sym->release(); 550 } 551 sym = NULL; 552 } 553 } else if (array) { 554 ok = array->setObject(o); 555 } else if (set) { 556 ok = set->setObject(o); 557 } else if (result) { 558 ok = false; 559 } else { 560 assert(!parent); 561 result = o; 562 } 563 564 if (!ok) { 565 break; 566 } 567 568 if (end) { 569 parent = NULL; 570 } 571 if (newCollect) { 572 stackIdx++; 573 setAtIndex(stack, stackIdx, parent); 574 if (!ok) { 575 break; 576 } 577 DEBG("++stack[%d] %p\n", stackIdx, parent); 578 parent = o; 579 dict = newDict; 580 array = newArray; 581 set = newSet; 582 end = false; 583 } 584 585 if (end) { 586 while (stackIdx) { 587 parent = stackArray[stackIdx]; 588 DEBG("--stack[%d] %p\n", stackIdx, parent); 589 stackIdx--; 590 if (parent) { 591 break; 592 } 593 } 594 if (!parent) { 595 break; 596 } 597 set = NULL; 598 dict = NULL; 599 array = NULL; 600 if (!(dict = OSDynamicCast(OSDictionary, parent))) { 601 if (!(array = OSDynamicCast(OSArray, parent))) { 602 ok = (NULL != (set = OSDynamicCast(OSSet, parent))); 603 } 604 } 605 } 606 } 607 DEBG("ret %p\n", result); 608 609 if (!ok) { 610 result = NULL; 611 } 612 613 if (objsCapacity) { 614 for (len = (result != NULL); len < objsIdx; len++) { 615 objsArray[len]->release(); 616 } 617 kfree_type(OSObject *, objsCapacity, objsArray); 618 } 619 if (stackCapacity) { 620 kfree_type(OSObject *, stackCapacity, stackArray); 621 } 622 623 return result; 624 } 625 626 OSObject* 627 OSUnserializeXML( 628 const char * buffer, 629 OSSharedPtr<OSString>& errorString) 630 { 631 OSString* errorStringRaw = NULL; 632 OSObject* result = OSUnserializeXML(buffer, &errorStringRaw); 633 errorString.reset(errorStringRaw, OSNoRetain); 634 return result; 635 } 636 637 OSObject* 638 OSUnserializeXML( 639 const char * buffer, 640 size_t bufferSize, 641 OSSharedPtr<OSString> &errorString) 642 { 643 OSString* errorStringRaw = NULL; 644 OSObject* result = OSUnserializeXML(buffer, bufferSize, &errorStringRaw); 645 errorString.reset(errorStringRaw, OSNoRetain); 646 return result; 647 } 648 649 OSObject* 650 OSUnserializeBinary(const char *buffer, size_t bufferSize, OSSharedPtr<OSString>& errorString) 651 { 652 OSString* errorStringRaw = NULL; 653 OSObject* result = OSUnserializeBinary(buffer, bufferSize, &errorStringRaw); 654 errorString.reset(errorStringRaw, OSNoRetain); 655 return result; 656 } 657 658 OSObject* 659 OSUnserialize(const char *buffer, OSSharedPtr<OSString>& errorString) 660 { 661 OSString* errorStringRaw = NULL; 662 OSObject* result = OSUnserialize(buffer, &errorStringRaw); 663 errorString.reset(errorStringRaw, OSNoRetain); 664 return result; 665 } 666