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