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 static SECURITY_READ_ONLY_LATE(vm_map_t) alloc_map;
57 __startup_func
58 static void
getAllocMap(void)59 getAllocMap(void)
60 {
61 alloc_map = KHEAP_DATA_BUFFERS->kh_fallback_map;
62 }
63 STARTUP(ZALLOC, STARTUP_RANK_LAST, getAllocMap);
64
65 bool
initWithCapacity(unsigned int inCapacity)66 OSData::initWithCapacity(unsigned int inCapacity)
67 {
68 void *_data = NULL;
69
70 if (data) {
71 OSCONTAINER_ACCUMSIZE(-((size_t)capacity));
72 if (!inCapacity || (capacity < inCapacity)) {
73 // clean out old data's storage if it isn't big enough
74 if (capacity < page_size) {
75 kfree_data_container(data, capacity);
76 } else {
77 kmem_free(alloc_map, (vm_offset_t)data, capacity);
78 }
79 data = NULL;
80 capacity = 0;
81 }
82 }
83
84 if (!super::init()) {
85 return false;
86 }
87
88 if (inCapacity && !data) {
89 if (inCapacity < page_size) {
90 data = (void *)kalloc_data_container(inCapacity, Z_WAITOK);
91 } else {
92 kern_return_t kr;
93 if (round_page_overflow(inCapacity, &inCapacity)) {
94 kr = KERN_RESOURCE_SHORTAGE;
95 } else {
96 kr = kernel_memory_allocate(alloc_map,
97 (vm_offset_t *)&_data, inCapacity,
98 0, KMA_ATOMIC, IOMemoryTag(alloc_map));
99 data = _data;
100 }
101 if (KERN_SUCCESS != kr) {
102 data = NULL;
103 }
104 }
105 if (!data) {
106 return false;
107 }
108 capacity = inCapacity;
109 }
110 OSCONTAINER_ACCUMSIZE(capacity);
111
112 length = 0;
113 if (inCapacity < 16) {
114 capacityIncrement = 16;
115 } else {
116 capacityIncrement = inCapacity;
117 }
118
119 return true;
120 }
121
122 bool
initWithBytes(const void * bytes,unsigned int inLength)123 OSData::initWithBytes(const void *bytes, unsigned int inLength)
124 {
125 if ((inLength && !bytes) || !initWithCapacity(inLength)) {
126 return false;
127 }
128
129 if (bytes != data) {
130 bcopy(bytes, data, inLength);
131 }
132 length = inLength;
133
134 return true;
135 }
136
137 bool
initWithBytesNoCopy(void * bytes,unsigned int inLength)138 OSData::initWithBytesNoCopy(void *bytes, unsigned int inLength)
139 {
140 if (!super::init()) {
141 return false;
142 }
143
144 length = inLength;
145 capacity = EXTERNAL;
146 data = bytes;
147
148 return true;
149 }
150
151 bool
initWithData(const OSData * inData)152 OSData::initWithData(const OSData *inData)
153 {
154 return initWithBytes(inData->data, inData->length);
155 }
156
157 bool
initWithData(const OSData * inData,unsigned int start,unsigned int inLength)158 OSData::initWithData(const OSData *inData,
159 unsigned int start, unsigned int inLength)
160 {
161 const void *localData = inData->getBytesNoCopy(start, inLength);
162
163 if (localData) {
164 return initWithBytes(localData, inLength);
165 } else {
166 return false;
167 }
168 }
169
170 OSSharedPtr<OSData>
withCapacity(unsigned int inCapacity)171 OSData::withCapacity(unsigned int inCapacity)
172 {
173 OSSharedPtr<OSData> me = OSMakeShared<OSData>();
174
175 if (me && !me->initWithCapacity(inCapacity)) {
176 return nullptr;
177 }
178
179 return me;
180 }
181
182 OSSharedPtr<OSData>
withBytes(const void * bytes,unsigned int inLength)183 OSData::withBytes(const void *bytes, unsigned int inLength)
184 {
185 OSSharedPtr<OSData> me = OSMakeShared<OSData>();
186
187 if (me && !me->initWithBytes(bytes, inLength)) {
188 return nullptr;
189 }
190 return me;
191 }
192
193 OSSharedPtr<OSData>
withBytesNoCopy(void * bytes,unsigned int inLength)194 OSData::withBytesNoCopy(void *bytes, unsigned int inLength)
195 {
196 OSSharedPtr<OSData> me = OSMakeShared<OSData>();
197
198 if (me && !me->initWithBytesNoCopy(bytes, inLength)) {
199 return nullptr;
200 }
201
202 return me;
203 }
204
205 OSSharedPtr<OSData>
withData(const OSData * inData)206 OSData::withData(const OSData *inData)
207 {
208 OSSharedPtr<OSData> me = OSMakeShared<OSData>();
209
210 if (me && !me->initWithData(inData)) {
211 return nullptr;
212 }
213
214 return me;
215 }
216
217 OSSharedPtr<OSData>
withData(const OSData * inData,unsigned int start,unsigned int inLength)218 OSData::withData(const OSData *inData,
219 unsigned int start, unsigned int inLength)
220 {
221 OSSharedPtr<OSData> me = OSMakeShared<OSData>();
222
223 if (me && !me->initWithData(inData, start, inLength)) {
224 return nullptr;
225 }
226
227 return me;
228 }
229
230 void
free()231 OSData::free()
232 {
233 if ((capacity != EXTERNAL) && data && capacity) {
234 if (capacity < page_size) {
235 kfree_data_container(data, capacity);
236 } else {
237 kmem_free(alloc_map, (vm_offset_t)data, capacity);
238 }
239 OSCONTAINER_ACCUMSIZE( -((size_t)capacity));
240 } else if (capacity == EXTERNAL) {
241 DeallocFunction freemem = reserved ? reserved->deallocFunction : NULL;
242 if (freemem && data && length) {
243 freemem(data, length);
244 }
245 }
246 if (reserved) {
247 kfree_type(ExpansionData, reserved);
248 }
249 super::free();
250 }
251
252 unsigned int
getLength() const253 OSData::getLength() const
254 {
255 return length;
256 }
257 unsigned int
getCapacity() const258 OSData::getCapacity() const
259 {
260 return capacity;
261 }
262
263 unsigned int
getCapacityIncrement() const264 OSData::getCapacityIncrement() const
265 {
266 return capacityIncrement;
267 }
268
269 unsigned int
setCapacityIncrement(unsigned increment)270 OSData::setCapacityIncrement(unsigned increment)
271 {
272 return capacityIncrement = increment;
273 }
274
275 // xx-review: does not check for capacity == EXTERNAL
276
277 unsigned int
ensureCapacity(unsigned int newCapacity)278 OSData::ensureCapacity(unsigned int newCapacity)
279 {
280 unsigned char * newData;
281 unsigned int finalCapacity;
282 void * copydata;
283 kern_return_t kr;
284
285 if (newCapacity <= capacity) {
286 return capacity;
287 }
288
289 finalCapacity = (((newCapacity - 1) / capacityIncrement) + 1)
290 * capacityIncrement;
291
292 // integer overflow check
293 if (finalCapacity < newCapacity) {
294 return capacity;
295 }
296
297 copydata = data;
298
299 if (finalCapacity >= page_size) {
300 // round up
301 finalCapacity = round_page_32(finalCapacity);
302 // integer overflow check
303 if (finalCapacity < newCapacity) {
304 return capacity;
305 }
306 if (capacity >= page_size) {
307 copydata = NULL;
308 kr = kmem_realloc(alloc_map,
309 (vm_offset_t)data,
310 capacity,
311 (vm_offset_t *)&newData,
312 finalCapacity,
313 IOMemoryTag(alloc_map));
314 } else {
315 kr = kernel_memory_allocate(alloc_map, (vm_offset_t *)&newData,
316 finalCapacity, 0, KMA_ATOMIC, IOMemoryTag(alloc_map));
317 }
318 if (KERN_SUCCESS != kr) {
319 newData = NULL;
320 }
321 } else {
322 newData = (unsigned char *)kalloc_data_container(finalCapacity, Z_WAITOK);
323 }
324
325 if (newData) {
326 bzero(newData + capacity, finalCapacity - capacity);
327 if (copydata) {
328 bcopy(copydata, newData, capacity);
329 }
330 if (data) {
331 if (capacity < page_size) {
332 kfree_data_container(data, capacity);
333 } else {
334 kmem_free(alloc_map, (vm_offset_t)data, capacity);
335 }
336 }
337 OSCONTAINER_ACCUMSIZE(((size_t)finalCapacity) - ((size_t)capacity));
338 data = (void *) newData;
339 capacity = finalCapacity;
340 }
341
342 return capacity;
343 }
344
345 bool
appendBytes(const void * bytes,unsigned int inLength)346 OSData::appendBytes(const void *bytes, unsigned int inLength)
347 {
348 unsigned int newSize;
349
350 if (!inLength) {
351 return true;
352 }
353
354 if (capacity == EXTERNAL) {
355 return false;
356 }
357
358 if (os_add_overflow(length, inLength, &newSize)) {
359 return false;
360 }
361
362 if ((newSize > capacity) && newSize > ensureCapacity(newSize)) {
363 return false;
364 }
365
366 if (bytes) {
367 bcopy(bytes, &((unsigned char *)data)[length], inLength);
368 } else {
369 bzero(&((unsigned char *)data)[length], inLength);
370 }
371
372 length = newSize;
373
374 return true;
375 }
376
377 bool
appendByte(unsigned char byte,unsigned int inLength)378 OSData::appendByte(unsigned char byte, unsigned int inLength)
379 {
380 unsigned int newSize;
381
382 if (!inLength) {
383 return true;
384 }
385
386 if (capacity == EXTERNAL) {
387 return false;
388 }
389
390 if (os_add_overflow(length, inLength, &newSize)) {
391 return false;
392 }
393
394 if ((newSize > capacity) && newSize > ensureCapacity(newSize)) {
395 return false;
396 }
397
398 memset(&((unsigned char *)data)[length], byte, inLength);
399 length = newSize;
400
401 return true;
402 }
403
404 bool
appendBytes(const OSData * other)405 OSData::appendBytes(const OSData *other)
406 {
407 return appendBytes(other->data, other->length);
408 }
409
410 const void *
getBytesNoCopy() const411 OSData::getBytesNoCopy() const
412 {
413 if (!length) {
414 return NULL;
415 } else {
416 return data;
417 }
418 }
419
420 const void *
getBytesNoCopy(unsigned int start,unsigned int inLength) const421 OSData::getBytesNoCopy(unsigned int start,
422 unsigned int inLength) const
423 {
424 const void *outData = NULL;
425
426 if (length
427 && start < length
428 && (start + inLength) >= inLength // overflow check
429 && (start + inLength) <= length) {
430 outData = (const void *) ((char *) data + start);
431 }
432
433 return outData;
434 }
435
436 bool
isEqualTo(const OSData * aData) const437 OSData::isEqualTo(const OSData *aData) const
438 {
439 unsigned int len;
440
441 len = aData->length;
442 if (length != len) {
443 return false;
444 }
445
446 return isEqualTo(aData->data, len);
447 }
448
449 bool
isEqualTo(const void * someData,unsigned int inLength) const450 OSData::isEqualTo(const void *someData, unsigned int inLength) const
451 {
452 return (length >= inLength) && (bcmp(data, someData, inLength) == 0);
453 }
454
455 bool
isEqualTo(const OSMetaClassBase * obj) const456 OSData::isEqualTo(const OSMetaClassBase *obj) const
457 {
458 OSData * otherData;
459 OSString * str;
460
461 if ((otherData = OSDynamicCast(OSData, obj))) {
462 return isEqualTo(otherData);
463 } else if ((str = OSDynamicCast(OSString, obj))) {
464 return isEqualTo(str);
465 } else {
466 return false;
467 }
468 }
469
470 bool
isEqualTo(const OSString * obj) const471 OSData::isEqualTo(const OSString *obj) const
472 {
473 const char * aCString;
474 char * dataPtr;
475 unsigned int checkLen = length;
476 unsigned int stringLen;
477
478 if (!obj) {
479 return false;
480 }
481
482 stringLen = obj->getLength();
483
484 dataPtr = (char *)data;
485
486 if (stringLen != checkLen) {
487 // check for the fact that OSData may be a buffer that
488 // that includes a termination byte and will thus have
489 // a length of the actual string length PLUS 1. In this
490 // case we verify that the additional byte is a terminator
491 // and if so count the two lengths as being the same.
492
493 if ((checkLen - stringLen) == 1) {
494 if (dataPtr[checkLen - 1] != 0) { // non-zero means not a terminator and thus not likely the same
495 return false;
496 }
497 checkLen--;
498 } else {
499 return false;
500 }
501 }
502
503 aCString = obj->getCStringNoCopy();
504
505 for (unsigned int i = 0; i < checkLen; i++) {
506 if (*dataPtr++ != aCString[i]) {
507 return false;
508 }
509 }
510
511 return true;
512 }
513
514 //this was taken from CFPropertyList.c
515 static const char __CFPLDataEncodeTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
516
517 bool
serialize(OSSerialize * s) const518 OSData::serialize(OSSerialize *s) const
519 {
520 unsigned int i;
521 const unsigned char *p;
522 unsigned char c;
523 unsigned int serializeLength;
524
525 if (s->previouslySerialized(this)) {
526 return true;
527 }
528
529 if (!s->addXMLStartTag(this, "data")) {
530 return false;
531 }
532
533 serializeLength = length;
534 if (reserved && reserved->disableSerialization) {
535 serializeLength = 0;
536 }
537
538 for (i = 0, p = (unsigned char *)data; i < serializeLength; i++, p++) {
539 /* 3 bytes are encoded as 4 */
540 switch (i % 3) {
541 case 0:
542 c = __CFPLDataEncodeTable[((p[0] >> 2) & 0x3f)];
543 if (!s->addChar(c)) {
544 return false;
545 }
546 break;
547 case 1:
548 c = __CFPLDataEncodeTable[((((p[-1] << 8) | p[0]) >> 4) & 0x3f)];
549 if (!s->addChar(c)) {
550 return false;
551 }
552 break;
553 case 2:
554 c = __CFPLDataEncodeTable[((((p[-1] << 8) | p[0]) >> 6) & 0x3f)];
555 if (!s->addChar(c)) {
556 return false;
557 }
558 c = __CFPLDataEncodeTable[(p[0] & 0x3f)];
559 if (!s->addChar(c)) {
560 return false;
561 }
562 break;
563 }
564 }
565 switch (i % 3) {
566 case 0:
567 break;
568 case 1:
569 c = __CFPLDataEncodeTable[((p[-1] << 4) & 0x30)];
570 if (!s->addChar(c)) {
571 return false;
572 }
573 if (!s->addChar('=')) {
574 return false;
575 }
576 if (!s->addChar('=')) {
577 return false;
578 }
579 break;
580 case 2:
581 c = __CFPLDataEncodeTable[((p[-1] << 2) & 0x3c)];
582 if (!s->addChar(c)) {
583 return false;
584 }
585 if (!s->addChar('=')) {
586 return false;
587 }
588 break;
589 }
590
591 return s->addXMLEndTag("data");
592 }
593
594 void
setDeallocFunction(DeallocFunction func)595 OSData::setDeallocFunction(DeallocFunction func)
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->deallocFunction = func;
604 }
605
606 void
setSerializable(bool serializable)607 OSData::setSerializable(bool serializable)
608 {
609 if (!reserved) {
610 reserved = (typeof(reserved))kalloc_type(ExpansionData, (zalloc_flags_t)(Z_WAITOK | Z_ZERO));
611 if (!reserved) {
612 return;
613 }
614 }
615 reserved->disableSerialization = (!serializable);
616 }
617
618 bool
isSerializable(void)619 OSData::isSerializable(void)
620 {
621 return !reserved || !reserved->disableSerialization;
622 }
623