1 /* 2 * Copyright (c) 2000 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 /* IOData.m created by rsulack on Thu 25-Sep-1997 */ 29 30 #include <string.h> 31 32 #include <vm/vm_kern.h> 33 34 #define IOKIT_ENABLE_SHARED_PTR 35 36 #include <libkern/c++/OSData.h> 37 #include <libkern/c++/OSSerialize.h> 38 #include <libkern/c++/OSLib.h> 39 #include <libkern/c++/OSString.h> 40 #include <IOKit/IOLib.h> 41 42 #define super OSObject 43 44 OSDefineMetaClassAndStructorsWithZone(OSData, OSObject, ZC_ZFREE_CLEARMEM) 45 OSMetaClassDefineReservedUsedX86(OSData, 0); // setDeallocFunction 46 OSMetaClassDefineReservedUnused(OSData, 1); 47 OSMetaClassDefineReservedUnused(OSData, 2); 48 OSMetaClassDefineReservedUnused(OSData, 3); 49 OSMetaClassDefineReservedUnused(OSData, 4); 50 OSMetaClassDefineReservedUnused(OSData, 5); 51 OSMetaClassDefineReservedUnused(OSData, 6); 52 OSMetaClassDefineReservedUnused(OSData, 7); 53 54 #define EXTERNAL ((unsigned int) -1) 55 56 bool 57 OSData::initWithCapacity(unsigned int inCapacity) 58 { 59 struct kalloc_result kr; 60 bool success = true; 61 62 if (!super::init()) { 63 return false; 64 } 65 66 /* 67 * OSData use of Z_MAY_COPYINMAP serves 2 purpposes: 68 * 69 * - It makes sure than when it goes to the VM, it uses its own object 70 * rather than the kernel object so that vm_map_copyin() can be used. 71 * 72 * - On Intel, it goes to the VM for any size >= PAGE_SIZE to maintain 73 * old (inefficient) ABI. On arm64 it will use kalloc_data() instead 74 * until the vm_map_copy_t msg_ool_size_small threshold for copies. 75 */ 76 77 if (inCapacity == 0) { 78 if (capacity) { 79 OSCONTAINER_ACCUMSIZE(-(size_t)capacity); 80 /* can't use kfree() as we need to pass Z_MAY_COPYINMAP */ 81 __kheap_realloc(KHEAP_DATA_BUFFERS, data, capacity, 0, 82 Z_VM_TAG_BT(Z_WAITOK_ZERO | Z_FULLSIZE | Z_MAY_COPYINMAP, 83 VM_KERN_MEMORY_LIBKERN), (void *)&this->data); 84 data = nullptr; 85 capacity = 0; 86 } 87 } else if (inCapacity <= capacity) { 88 /* 89 * Nothing to change 90 */ 91 } else { 92 kr = kalloc_ext(KHEAP_DATA_BUFFERS, inCapacity, 93 Z_VM_TAG_BT(Z_WAITOK_ZERO | Z_FULLSIZE | Z_MAY_COPYINMAP, 94 VM_KERN_MEMORY_LIBKERN), (void *)&this->data); 95 96 if (kr.addr) { 97 size_t delta = 0; 98 99 data = kr.addr; 100 delta -= capacity; 101 capacity = (uint32_t)MIN(kr.size, UINT32_MAX); 102 delta += capacity; 103 OSCONTAINER_ACCUMSIZE(delta); 104 } else { 105 success = false; 106 } 107 } 108 109 length = 0; 110 capacityIncrement = MAX(16, inCapacity); 111 112 return success; 113 } 114 115 bool 116 OSData::initWithBytes(const void *bytes, unsigned int inLength) 117 { 118 if ((inLength && !bytes) || !initWithCapacity(inLength)) { 119 return false; 120 } 121 122 if (bytes != data) { 123 bcopy(bytes, data, inLength); 124 } 125 length = inLength; 126 127 return true; 128 } 129 130 bool 131 OSData::initWithBytesNoCopy(void *bytes, unsigned int inLength) 132 { 133 if (!super::init()) { 134 return false; 135 } 136 137 length = inLength; 138 capacity = EXTERNAL; 139 data = bytes; 140 141 return true; 142 } 143 144 bool 145 OSData::initWithData(const OSData *inData) 146 { 147 return initWithBytes(inData->data, inData->length); 148 } 149 150 bool 151 OSData::initWithData(const OSData *inData, 152 unsigned int start, unsigned int inLength) 153 { 154 const void *localData = inData->getBytesNoCopy(start, inLength); 155 156 if (localData) { 157 return initWithBytes(localData, inLength); 158 } else { 159 return false; 160 } 161 } 162 163 OSSharedPtr<OSData> 164 OSData::withCapacity(unsigned int inCapacity) 165 { 166 OSSharedPtr<OSData> me = OSMakeShared<OSData>(); 167 168 if (me && !me->initWithCapacity(inCapacity)) { 169 return nullptr; 170 } 171 172 return me; 173 } 174 175 OSSharedPtr<OSData> 176 OSData::withBytes(const void *bytes, unsigned int inLength) 177 { 178 OSSharedPtr<OSData> me = OSMakeShared<OSData>(); 179 180 if (me && !me->initWithBytes(bytes, inLength)) { 181 return nullptr; 182 } 183 return me; 184 } 185 186 OSSharedPtr<OSData> 187 OSData::withBytesNoCopy(void *bytes, unsigned int inLength) 188 { 189 OSSharedPtr<OSData> me = OSMakeShared<OSData>(); 190 191 if (me && !me->initWithBytesNoCopy(bytes, inLength)) { 192 return nullptr; 193 } 194 195 return me; 196 } 197 198 OSSharedPtr<OSData> 199 OSData::withData(const OSData *inData) 200 { 201 OSSharedPtr<OSData> me = OSMakeShared<OSData>(); 202 203 if (me && !me->initWithData(inData)) { 204 return nullptr; 205 } 206 207 return me; 208 } 209 210 OSSharedPtr<OSData> 211 OSData::withData(const OSData *inData, 212 unsigned int start, unsigned int inLength) 213 { 214 OSSharedPtr<OSData> me = OSMakeShared<OSData>(); 215 216 if (me && !me->initWithData(inData, start, inLength)) { 217 return nullptr; 218 } 219 220 return me; 221 } 222 223 void 224 OSData::free() 225 { 226 if ((capacity != EXTERNAL) && data && capacity) { 227 /* can't use kfree() as we need to pass Z_MAY_COPYINMAP */ 228 __kheap_realloc(KHEAP_DATA_BUFFERS, data, capacity, 0, 229 Z_VM_TAG_BT(Z_WAITOK_ZERO | Z_FULLSIZE | Z_MAY_COPYINMAP, 230 VM_KERN_MEMORY_LIBKERN), (void *)&this->data); 231 OSCONTAINER_ACCUMSIZE( -((size_t)capacity)); 232 } else if (capacity == EXTERNAL) { 233 DeallocFunction freemem = reserved ? reserved->deallocFunction : NULL; 234 if (freemem && data && length) { 235 freemem(data, length); 236 } 237 } 238 if (reserved) { 239 kfree_type(ExpansionData, reserved); 240 } 241 super::free(); 242 } 243 244 unsigned int 245 OSData::getLength() const 246 { 247 return length; 248 } 249 unsigned int 250 OSData::getCapacity() const 251 { 252 return capacity; 253 } 254 255 unsigned int 256 OSData::getCapacityIncrement() const 257 { 258 return capacityIncrement; 259 } 260 261 unsigned int 262 OSData::setCapacityIncrement(unsigned increment) 263 { 264 return capacityIncrement = increment; 265 } 266 267 // xx-review: does not check for capacity == EXTERNAL 268 269 unsigned int 270 OSData::ensureCapacity(unsigned int newCapacity) 271 { 272 struct kalloc_result kr; 273 unsigned int finalCapacity; 274 275 if (newCapacity <= capacity) { 276 return capacity; 277 } 278 279 finalCapacity = (((newCapacity - 1) / capacityIncrement) + 1) 280 * capacityIncrement; 281 282 // integer overflow check 283 if (finalCapacity < newCapacity) { 284 return capacity; 285 } 286 287 kr = krealloc_ext((void *)KHEAP_DATA_BUFFERS, data, capacity, finalCapacity, 288 Z_VM_TAG_BT(Z_WAITOK_ZERO | Z_FULLSIZE | Z_MAY_COPYINMAP, 289 VM_KERN_MEMORY_LIBKERN), (void *)&this->data); 290 291 if (kr.addr) { 292 size_t delta = 0; 293 294 data = kr.addr; 295 delta -= capacity; 296 capacity = (uint32_t)MIN(kr.size, UINT32_MAX); 297 delta += capacity; 298 OSCONTAINER_ACCUMSIZE(delta); 299 } 300 301 return capacity; 302 } 303 304 bool 305 OSData::clipForCopyout() 306 { 307 unsigned int newCapacity = (uint32_t)round_page(length); 308 __assert_only struct kalloc_result kr; 309 310 /* 311 * OSData allocations are atomic, which means that if copyoutkdata() 312 * is used on them, and that there are fully unused pages at the end 313 * of the OSData buffer, then vm_map_copyin() will try to clip the VM 314 * entry which will panic. 315 * 316 * In order to avoid this, trim down the unused pages. 317 * 318 * We know this operation never fails and keeps the allocation 319 * address stable. 320 */ 321 if (length >= msg_ool_size_small && newCapacity < capacity) { 322 kr = krealloc_ext((void *)KHEAP_DATA_BUFFERS, 323 data, capacity, newCapacity, 324 Z_VM_TAG_BT(Z_WAITOK_ZERO | Z_FULLSIZE | Z_MAY_COPYINMAP, 325 VM_KERN_MEMORY_LIBKERN), (void *)&this->data); 326 assert(kr.addr == data); 327 OSCONTAINER_ACCUMSIZE(((size_t)newCapacity) - ((size_t)capacity)); 328 capacity = newCapacity; 329 } 330 return true; 331 } 332 333 bool 334 OSData::appendBytes(const void *bytes, unsigned int inLength) 335 { 336 unsigned int newSize; 337 338 if (!inLength) { 339 return true; 340 } 341 342 if (capacity == EXTERNAL) { 343 return false; 344 } 345 346 if (os_add_overflow(length, inLength, &newSize)) { 347 return false; 348 } 349 350 if ((newSize > capacity) && newSize > ensureCapacity(newSize)) { 351 return false; 352 } 353 354 if (bytes) { 355 bcopy(bytes, &((unsigned char *)data)[length], inLength); 356 } else { 357 bzero(&((unsigned char *)data)[length], inLength); 358 } 359 360 length = newSize; 361 362 return true; 363 } 364 365 bool 366 OSData::appendByte(unsigned char byte, unsigned int inLength) 367 { 368 unsigned int newSize; 369 370 if (!inLength) { 371 return true; 372 } 373 374 if (capacity == EXTERNAL) { 375 return false; 376 } 377 378 if (os_add_overflow(length, inLength, &newSize)) { 379 return false; 380 } 381 382 if ((newSize > capacity) && newSize > ensureCapacity(newSize)) { 383 return false; 384 } 385 386 memset(&((unsigned char *)data)[length], byte, inLength); 387 length = newSize; 388 389 return true; 390 } 391 392 bool 393 OSData::appendBytes(const OSData *other) 394 { 395 return appendBytes(other->data, other->length); 396 } 397 398 const void * 399 OSData::getBytesNoCopy() const 400 { 401 if (!length) { 402 return NULL; 403 } else { 404 return data; 405 } 406 } 407 408 const void * 409 OSData::getBytesNoCopy(unsigned int start, 410 unsigned int inLength) const 411 { 412 const void *outData = NULL; 413 414 if (length 415 && start < length 416 && (start + inLength) >= inLength // overflow check 417 && (start + inLength) <= length) { 418 outData = (const void *) ((char *) data + start); 419 } 420 421 return outData; 422 } 423 424 bool 425 OSData::isEqualTo(const OSData *aData) const 426 { 427 unsigned int len; 428 429 len = aData->length; 430 if (length != len) { 431 return false; 432 } 433 434 return isEqualTo(aData->data, len); 435 } 436 437 bool 438 OSData::isEqualTo(const void *someData, unsigned int inLength) const 439 { 440 return (length >= inLength) && (bcmp(data, someData, inLength) == 0); 441 } 442 443 bool 444 OSData::isEqualTo(const OSMetaClassBase *obj) const 445 { 446 OSData * otherData; 447 OSString * str; 448 449 if ((otherData = OSDynamicCast(OSData, obj))) { 450 return isEqualTo(otherData); 451 } else if ((str = OSDynamicCast(OSString, obj))) { 452 return isEqualTo(str); 453 } else { 454 return false; 455 } 456 } 457 458 bool 459 OSData::isEqualTo(const OSString *obj) const 460 { 461 const char * aCString; 462 char * dataPtr; 463 unsigned int checkLen = length; 464 unsigned int stringLen; 465 466 if (!obj) { 467 return false; 468 } 469 470 stringLen = obj->getLength(); 471 472 dataPtr = (char *)data; 473 474 if (stringLen != checkLen) { 475 // check for the fact that OSData may be a buffer that 476 // that includes a termination byte and will thus have 477 // a length of the actual string length PLUS 1. In this 478 // case we verify that the additional byte is a terminator 479 // and if so count the two lengths as being the same. 480 481 if ((checkLen - stringLen) == 1) { 482 if (dataPtr[checkLen - 1] != 0) { // non-zero means not a terminator and thus not likely the same 483 return false; 484 } 485 checkLen--; 486 } else { 487 return false; 488 } 489 } 490 491 aCString = obj->getCStringNoCopy(); 492 493 for (unsigned int i = 0; i < checkLen; i++) { 494 if (*dataPtr++ != aCString[i]) { 495 return false; 496 } 497 } 498 499 return true; 500 } 501 502 //this was taken from CFPropertyList.c 503 static const char __CFPLDataEncodeTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 504 505 bool 506 OSData::serialize(OSSerialize *s) const 507 { 508 unsigned int i; 509 const unsigned char *p; 510 unsigned char c; 511 unsigned int serializeLength; 512 513 if (s->previouslySerialized(this)) { 514 return true; 515 } 516 517 if (!s->addXMLStartTag(this, "data")) { 518 return false; 519 } 520 521 serializeLength = length; 522 if (reserved && reserved->disableSerialization) { 523 serializeLength = 0; 524 } 525 526 for (i = 0, p = (unsigned char *)data; i < serializeLength; i++, p++) { 527 /* 3 bytes are encoded as 4 */ 528 switch (i % 3) { 529 case 0: 530 c = __CFPLDataEncodeTable[((p[0] >> 2) & 0x3f)]; 531 if (!s->addChar(c)) { 532 return false; 533 } 534 break; 535 case 1: 536 c = __CFPLDataEncodeTable[((((p[-1] << 8) | p[0]) >> 4) & 0x3f)]; 537 if (!s->addChar(c)) { 538 return false; 539 } 540 break; 541 case 2: 542 c = __CFPLDataEncodeTable[((((p[-1] << 8) | p[0]) >> 6) & 0x3f)]; 543 if (!s->addChar(c)) { 544 return false; 545 } 546 c = __CFPLDataEncodeTable[(p[0] & 0x3f)]; 547 if (!s->addChar(c)) { 548 return false; 549 } 550 break; 551 } 552 } 553 switch (i % 3) { 554 case 0: 555 break; 556 case 1: 557 c = __CFPLDataEncodeTable[((p[-1] << 4) & 0x30)]; 558 if (!s->addChar(c)) { 559 return false; 560 } 561 if (!s->addChar('=')) { 562 return false; 563 } 564 if (!s->addChar('=')) { 565 return false; 566 } 567 break; 568 case 2: 569 c = __CFPLDataEncodeTable[((p[-1] << 2) & 0x3c)]; 570 if (!s->addChar(c)) { 571 return false; 572 } 573 if (!s->addChar('=')) { 574 return false; 575 } 576 break; 577 } 578 579 return s->addXMLEndTag("data"); 580 } 581 582 void 583 OSData::setDeallocFunction(DeallocFunction func) 584 { 585 if (!reserved) { 586 reserved = (typeof(reserved))kalloc_type(ExpansionData, (zalloc_flags_t)(Z_WAITOK | Z_ZERO)); 587 if (!reserved) { 588 return; 589 } 590 } 591 reserved->deallocFunction = func; 592 } 593 594 void 595 OSData::setSerializable(bool serializable) 596 { 597 if (!reserved) { 598 reserved = (typeof(reserved))kalloc_type(ExpansionData, (zalloc_flags_t)(Z_WAITOK | Z_ZERO)); 599 if (!reserved) { 600 return; 601 } 602 } 603 reserved->disableSerialization = (!serializable); 604 } 605 606 bool 607 OSData::isSerializable(void) 608 { 609 return !reserved || !reserved->disableSerialization; 610 } 611