1 | /* |
2 | * Copyright (c) 1998-2019 Apple 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 | #include <libkern/c++/OSKext.h> |
30 | #include <libkern/c++/OSSharedPtr.h> |
31 | #include <IOKit/IOKitServer.h> |
32 | #include <IOKit/IOKitKeysPrivate.h> |
33 | #include <IOKit/IOUserClient.h> |
34 | #include <IOKit/IOService.h> |
35 | #include <IOKit/IORegistryEntry.h> |
36 | #include <IOKit/IOCatalogue.h> |
37 | #include <IOKit/IOMemoryDescriptor.h> |
38 | #include <IOKit/IOBufferMemoryDescriptor.h> |
39 | #include <IOKit/IOLib.h> |
40 | #include <IOKit/IOBSD.h> |
41 | #include <IOKit/IOStatisticsPrivate.h> |
42 | #include <IOKit/IOTimeStamp.h> |
43 | #include <IOKit/IODeviceTreeSupport.h> |
44 | #include <IOKit/IOUserServer.h> |
45 | #include <IOKit/system.h> |
46 | #include <libkern/OSDebug.h> |
47 | #include <DriverKit/OSAction.h> |
48 | #include <sys/proc.h> |
49 | #include <sys/kauth.h> |
50 | #include <sys/codesign.h> |
51 | #include <sys/code_signing.h> |
52 | |
53 | #include <mach/sdt.h> |
54 | #include <os/hash.h> |
55 | |
56 | #include <libkern/amfi/amfi.h> |
57 | |
58 | #if CONFIG_MACF |
59 | |
60 | extern "C" { |
61 | #include <security/mac_framework.h> |
62 | }; |
63 | #include <sys/kauth.h> |
64 | |
65 | #define IOMACF_LOG 0 |
66 | |
67 | #endif /* CONFIG_MACF */ |
68 | |
69 | #include <IOKit/assert.h> |
70 | |
71 | #include "IOServicePrivate.h" |
72 | #include "IOKitKernelInternal.h" |
73 | |
74 | #define SCALAR64(x) ((io_user_scalar_t)((unsigned int)x)) |
75 | #define SCALAR32(x) ((uint32_t )x) |
76 | #define ARG32(x) ((void *)(uintptr_t)SCALAR32(x)) |
77 | #define REF64(x) ((io_user_reference_t)((UInt64)(x))) |
78 | #define REF32(x) ((int)(x)) |
79 | |
80 | enum{ |
81 | kIOUCAsync0Flags = 3ULL, |
82 | kIOUCAsync64Flag = 1ULL, |
83 | kIOUCAsyncErrorLoggedFlag = 2ULL |
84 | }; |
85 | |
86 | #if IOKITSTATS |
87 | |
88 | #define IOStatisticsRegisterCounter() \ |
89 | do { \ |
90 | reserved->counter = IOStatistics::registerUserClient(this); \ |
91 | } while (0) |
92 | |
93 | #define IOStatisticsUnregisterCounter() \ |
94 | do { \ |
95 | if (reserved) \ |
96 | IOStatistics::unregisterUserClient(reserved->counter); \ |
97 | } while (0) |
98 | |
99 | #define IOStatisticsClientCall() \ |
100 | do { \ |
101 | IOStatistics::countUserClientCall(client); \ |
102 | } while (0) |
103 | |
104 | #else |
105 | |
106 | #define IOStatisticsRegisterCounter() |
107 | #define IOStatisticsUnregisterCounter() |
108 | #define IOStatisticsClientCall() |
109 | |
110 | #endif /* IOKITSTATS */ |
111 | |
112 | #if DEVELOPMENT || DEBUG |
113 | |
114 | #define FAKE_STACK_FRAME(a) \ |
115 | const void ** __frameptr; \ |
116 | const void * __retaddr; \ |
117 | __frameptr = (typeof(__frameptr)) __builtin_frame_address(0); \ |
118 | __retaddr = __frameptr[1]; \ |
119 | __frameptr[1] = (a); |
120 | |
121 | #define FAKE_STACK_FRAME_END() \ |
122 | __frameptr[1] = __retaddr; |
123 | |
124 | #else /* DEVELOPMENT || DEBUG */ |
125 | |
126 | #define FAKE_STACK_FRAME(a) |
127 | #define FAKE_STACK_FRAME_END() |
128 | |
129 | #endif /* DEVELOPMENT || DEBUG */ |
130 | |
131 | #define ASYNC_REF_COUNT (sizeof(io_async_ref_t) / sizeof(natural_t)) |
132 | #define ASYNC_REF64_COUNT (sizeof(io_async_ref64_t) / sizeof(io_user_reference_t)) |
133 | |
134 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
135 | |
136 | extern "C" { |
137 | #include <mach/mach_traps.h> |
138 | #include <vm/vm_map.h> |
139 | } /* extern "C" */ |
140 | |
141 | struct IOMachPortHashList; |
142 | |
143 | static_assert(IKOT_MAX_TYPE <= 255); |
144 | |
145 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
146 | |
147 | // IOMachPort maps OSObjects to ports, avoiding adding an ivar to OSObject. |
148 | class IOMachPort : public OSObject |
149 | { |
150 | OSDeclareDefaultStructors(IOMachPort); |
151 | public: |
152 | mach_port_mscount_t mscount; |
153 | IOLock lock; |
154 | SLIST_ENTRY(IOMachPort) link; |
155 | ipc_port_t port; |
156 | OSObject* XNU_PTRAUTH_SIGNED_PTR("IOMachPort.object" ) object; |
157 | |
158 | static IOMachPort* withObjectAndType(OSObject *obj, ipc_kobject_type_t type); |
159 | |
160 | static IOMachPortHashList* bucketForObject(OSObject *obj, |
161 | ipc_kobject_type_t type); |
162 | |
163 | static LIBKERN_RETURNS_NOT_RETAINED IOMachPort* portForObjectInBucket(IOMachPortHashList *bucket, OSObject *obj, ipc_kobject_type_t type); |
164 | |
165 | static bool noMoreSendersForObject( OSObject * obj, |
166 | ipc_kobject_type_t type, mach_port_mscount_t * mscount ); |
167 | static void releasePortForObject( OSObject * obj, |
168 | ipc_kobject_type_t type ); |
169 | |
170 | static mach_port_name_t makeSendRightForTask( task_t task, |
171 | io_object_t obj, ipc_kobject_type_t type ); |
172 | |
173 | virtual void free() APPLE_KEXT_OVERRIDE; |
174 | }; |
175 | |
176 | #define super OSObject |
177 | OSDefineMetaClassAndStructorsWithZone(IOMachPort, OSObject, ZC_ZFREE_CLEARMEM) |
178 | |
179 | static IOLock * gIOObjectPortLock; |
180 | IOLock * gIOUserServerLock; |
181 | |
182 | SECURITY_READ_ONLY_LATE(const struct io_filter_callbacks *) gIOUCFilterCallbacks; |
183 | |
184 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
185 | |
186 | SLIST_HEAD(IOMachPortHashList, IOMachPort); |
187 | |
188 | #if defined(XNU_TARGET_OS_OSX) |
189 | #define PORT_HASH_SIZE 4096 |
190 | #else /* defined(!XNU_TARGET_OS_OSX) */ |
191 | #define PORT_HASH_SIZE 256 |
192 | #endif /* !defined(!XNU_TARGET_OS_OSX) */ |
193 | |
194 | IOMachPortHashList gIOMachPortHash[PORT_HASH_SIZE]; |
195 | |
196 | void |
197 | IOMachPortInitialize(void) |
198 | { |
199 | for (size_t i = 0; i < PORT_HASH_SIZE; i++) { |
200 | SLIST_INIT(&gIOMachPortHash[i]); |
201 | } |
202 | } |
203 | |
204 | IOMachPortHashList* |
205 | IOMachPort::bucketForObject(OSObject *obj, ipc_kobject_type_t type ) |
206 | { |
207 | return &gIOMachPortHash[os_hash_kernel_pointer(pointer: obj) % PORT_HASH_SIZE]; |
208 | } |
209 | |
210 | IOMachPort* |
211 | IOMachPort::portForObjectInBucket(IOMachPortHashList *bucket, OSObject *obj, ipc_kobject_type_t type) |
212 | { |
213 | IOMachPort *machPort; |
214 | |
215 | SLIST_FOREACH(machPort, bucket, link) { |
216 | if (machPort->object == obj && iokit_port_type(port: machPort->port) == type) { |
217 | return machPort; |
218 | } |
219 | } |
220 | return NULL; |
221 | } |
222 | |
223 | IOMachPort* |
224 | IOMachPort::withObjectAndType(OSObject *obj, ipc_kobject_type_t type) |
225 | { |
226 | IOMachPort *machPort = NULL; |
227 | |
228 | machPort = new IOMachPort; |
229 | if (__improbable(machPort && !machPort->init())) { |
230 | OSSafeReleaseNULL(machPort); |
231 | return NULL; |
232 | } |
233 | |
234 | machPort->object = obj; |
235 | machPort->port = iokit_alloc_object_port(obj: machPort, type); |
236 | IOLockInlineInit(&machPort->lock); |
237 | |
238 | obj->taggedRetain(OSTypeID(OSCollection)); |
239 | machPort->mscount++; |
240 | |
241 | return machPort; |
242 | } |
243 | |
244 | bool |
245 | IOMachPort::noMoreSendersForObject( OSObject * obj, |
246 | ipc_kobject_type_t type, mach_port_mscount_t * mscount ) |
247 | { |
248 | IOMachPort *machPort = NULL; |
249 | IOUserClient *uc; |
250 | OSAction *action; |
251 | bool destroyed = true; |
252 | |
253 | IOMachPortHashList *bucket = IOMachPort::bucketForObject(obj, type); |
254 | |
255 | obj->retain(); |
256 | |
257 | lck_mtx_lock(lck: gIOObjectPortLock); |
258 | |
259 | machPort = IOMachPort::portForObjectInBucket(bucket, obj, type); |
260 | |
261 | if (machPort) { |
262 | destroyed = (machPort->mscount <= *mscount); |
263 | if (!destroyed) { |
264 | *mscount = machPort->mscount; |
265 | lck_mtx_unlock(lck: gIOObjectPortLock); |
266 | } else { |
267 | if ((IKOT_IOKIT_CONNECT == type) && (uc = OSDynamicCast(IOUserClient, obj))) { |
268 | uc->noMoreSenders(); |
269 | } |
270 | SLIST_REMOVE(bucket, machPort, IOMachPort, link); |
271 | |
272 | IOLockLock(&machPort->lock); |
273 | iokit_remove_object_port(port: machPort->port, type); |
274 | machPort->object = NULL; |
275 | IOLockUnlock(&machPort->lock); |
276 | |
277 | lck_mtx_unlock(lck: gIOObjectPortLock); |
278 | |
279 | OS_ANALYZER_SUPPRESS("77508635" ) OSSafeReleaseNULL(machPort); |
280 | |
281 | obj->taggedRelease(OSTypeID(OSCollection)); |
282 | } |
283 | } else { |
284 | lck_mtx_unlock(lck: gIOObjectPortLock); |
285 | } |
286 | |
287 | if ((IKOT_UEXT_OBJECT == type) && (action = OSDynamicCast(OSAction, obj))) { |
288 | action->Aborted(); |
289 | } |
290 | |
291 | if (IKOT_UEXT_OBJECT == type && IOUserServer::shouldLeakObjects()) { |
292 | // Leak object |
293 | obj->retain(); |
294 | } |
295 | |
296 | obj->release(); |
297 | |
298 | return destroyed; |
299 | } |
300 | |
301 | void |
302 | IOMachPort::releasePortForObject( OSObject * obj, |
303 | ipc_kobject_type_t type ) |
304 | { |
305 | IOMachPort *machPort; |
306 | IOService *service; |
307 | IOMachPortHashList *bucket = IOMachPort::bucketForObject(obj, type); |
308 | |
309 | assert(IKOT_IOKIT_CONNECT != type); |
310 | |
311 | lck_mtx_lock(lck: gIOObjectPortLock); |
312 | |
313 | machPort = IOMachPort::portForObjectInBucket(bucket, obj, type); |
314 | |
315 | if (machPort |
316 | && (type == IKOT_IOKIT_OBJECT) |
317 | && (service = OSDynamicCast(IOService, obj)) |
318 | && !service->machPortHoldDestroy()) { |
319 | obj->retain(); |
320 | SLIST_REMOVE(bucket, machPort, IOMachPort, link); |
321 | |
322 | IOLockLock(&machPort->lock); |
323 | iokit_remove_object_port(port: machPort->port, type); |
324 | machPort->object = NULL; |
325 | IOLockUnlock(&machPort->lock); |
326 | |
327 | lck_mtx_unlock(lck: gIOObjectPortLock); |
328 | |
329 | OS_ANALYZER_SUPPRESS("77508635" ) OSSafeReleaseNULL(machPort); |
330 | |
331 | obj->taggedRelease(OSTypeID(OSCollection)); |
332 | obj->release(); |
333 | } else { |
334 | lck_mtx_unlock(lck: gIOObjectPortLock); |
335 | } |
336 | } |
337 | |
338 | void |
339 | IOUserClient::destroyUserReferences( OSObject * obj ) |
340 | { |
341 | IOMachPort *machPort; |
342 | bool destroyPort; |
343 | |
344 | IOMachPort::releasePortForObject( obj, type: IKOT_IOKIT_OBJECT ); |
345 | |
346 | // panther, 3160200 |
347 | // IOMachPort::releasePortForObject( obj, IKOT_IOKIT_CONNECT ); |
348 | |
349 | obj->retain(); |
350 | IOMachPortHashList *bucket = IOMachPort::bucketForObject(obj, type: IKOT_IOKIT_CONNECT); |
351 | IOMachPortHashList *mappingBucket = NULL; |
352 | |
353 | lck_mtx_lock(lck: gIOObjectPortLock); |
354 | |
355 | IOUserClient * uc = OSDynamicCast(IOUserClient, obj); |
356 | if (uc && uc->mappings) { |
357 | mappingBucket = IOMachPort::bucketForObject(obj: uc->mappings, type: IKOT_IOKIT_CONNECT); |
358 | } |
359 | |
360 | machPort = IOMachPort::portForObjectInBucket(bucket, obj, type: IKOT_IOKIT_CONNECT); |
361 | |
362 | if (machPort == NULL) { |
363 | lck_mtx_unlock(lck: gIOObjectPortLock); |
364 | goto end; |
365 | } |
366 | |
367 | SLIST_REMOVE(bucket, machPort, IOMachPort, link); |
368 | obj->taggedRelease(OSTypeID(OSCollection)); |
369 | |
370 | destroyPort = true; |
371 | if (uc) { |
372 | uc->noMoreSenders(); |
373 | if (uc->mappings) { |
374 | uc->mappings->taggedRetain(OSTypeID(OSCollection)); |
375 | SLIST_INSERT_HEAD(mappingBucket, machPort, link); |
376 | |
377 | IOLockLock(&machPort->lock); |
378 | machPort->object = uc->mappings; |
379 | IOLockUnlock(&machPort->lock); |
380 | |
381 | lck_mtx_unlock(lck: gIOObjectPortLock); |
382 | |
383 | OSSafeReleaseNULL(uc->mappings); |
384 | destroyPort = false; |
385 | } |
386 | } |
387 | |
388 | if (destroyPort) { |
389 | IOLockLock(&machPort->lock); |
390 | iokit_remove_object_port(port: machPort->port, type: IKOT_IOKIT_CONNECT); |
391 | machPort->object = NULL; |
392 | IOLockUnlock(&machPort->lock); |
393 | |
394 | lck_mtx_unlock(lck: gIOObjectPortLock); |
395 | OS_ANALYZER_SUPPRESS("77508635" ) OSSafeReleaseNULL(machPort); |
396 | } |
397 | |
398 | end: |
399 | OSSafeReleaseNULL(obj); |
400 | } |
401 | |
402 | mach_port_name_t |
403 | IOMachPort::makeSendRightForTask( task_t task, |
404 | io_object_t obj, ipc_kobject_type_t type ) |
405 | { |
406 | return iokit_make_send_right( task, obj, type ); |
407 | } |
408 | |
409 | void |
410 | IOMachPort::free( void ) |
411 | { |
412 | if (port) { |
413 | iokit_destroy_object_port(port, type: iokit_port_type(port)); |
414 | } |
415 | IOLockInlineDestroy(&lock); |
416 | super::free(); |
417 | } |
418 | |
419 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
420 | |
421 | static bool |
422 | IOTaskRegistryCompatibility(task_t task) |
423 | { |
424 | return false; |
425 | } |
426 | |
427 | static void |
428 | IOTaskRegistryCompatibilityMatching(task_t task, OSDictionary * matching) |
429 | { |
430 | matching->setObject(aKey: gIOServiceNotificationUserKey, anObject: kOSBooleanTrue); |
431 | if (!IOTaskRegistryCompatibility(task)) { |
432 | return; |
433 | } |
434 | matching->setObject(aKey: gIOCompatibilityMatchKey, anObject: kOSBooleanTrue); |
435 | } |
436 | |
437 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
438 | |
439 | OSDefineMetaClassAndStructors( IOUserIterator, OSIterator ) |
440 | |
441 | IOUserIterator * |
442 | IOUserIterator::withIterator(OSIterator * iter) |
443 | { |
444 | IOUserIterator * me; |
445 | |
446 | if (!iter) { |
447 | return NULL; |
448 | } |
449 | |
450 | me = new IOUserIterator; |
451 | if (me && !me->init()) { |
452 | me->release(); |
453 | me = NULL; |
454 | } |
455 | if (!me) { |
456 | iter->release(); |
457 | return me; |
458 | } |
459 | me->userIteratorObject = iter; |
460 | |
461 | return me; |
462 | } |
463 | |
464 | bool |
465 | IOUserIterator::init( void ) |
466 | { |
467 | if (!OSObject::init()) { |
468 | return false; |
469 | } |
470 | |
471 | IOLockInlineInit(&lock); |
472 | return true; |
473 | } |
474 | |
475 | void |
476 | IOUserIterator::free() |
477 | { |
478 | if (userIteratorObject) { |
479 | userIteratorObject->release(); |
480 | } |
481 | IOLockInlineDestroy(&lock); |
482 | OSObject::free(); |
483 | } |
484 | |
485 | void |
486 | IOUserIterator::reset() |
487 | { |
488 | IOLockLock(&lock); |
489 | assert(OSDynamicCast(OSIterator, userIteratorObject)); |
490 | ((OSIterator *)userIteratorObject)->reset(); |
491 | IOLockUnlock(&lock); |
492 | } |
493 | |
494 | bool |
495 | IOUserIterator::isValid() |
496 | { |
497 | bool ret; |
498 | |
499 | IOLockLock(&lock); |
500 | assert(OSDynamicCast(OSIterator, userIteratorObject)); |
501 | ret = ((OSIterator *)userIteratorObject)->isValid(); |
502 | IOLockUnlock(&lock); |
503 | |
504 | return ret; |
505 | } |
506 | |
507 | OSObject * |
508 | IOUserIterator::getNextObject() |
509 | { |
510 | assert(false); |
511 | return NULL; |
512 | } |
513 | |
514 | OSObject * |
515 | IOUserIterator::copyNextObject() |
516 | { |
517 | OSObject * ret = NULL; |
518 | |
519 | IOLockLock(&lock); |
520 | if (userIteratorObject) { |
521 | ret = ((OSIterator *)userIteratorObject)->getNextObject(); |
522 | if (ret) { |
523 | ret->retain(); |
524 | } |
525 | } |
526 | IOLockUnlock(&lock); |
527 | |
528 | return ret; |
529 | } |
530 | |
531 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
532 | extern "C" { |
533 | // functions called from osfmk/device/iokit_rpc.c |
534 | |
535 | void |
536 | iokit_port_object_description(io_object_t obj, kobject_description_t desc) |
537 | { |
538 | IORegistryEntry * regEntry; |
539 | IOUserNotification * __unused noti; |
540 | _IOServiceNotifier * __unused serviceNoti; |
541 | OSSerialize * __unused s; |
542 | OSDictionary * __unused matching = NULL; |
543 | |
544 | if ((regEntry = OSDynamicCast(IORegistryEntry, obj))) { |
545 | snprintf(desc, KOBJECT_DESCRIPTION_LENGTH, "%s(0x%qx)" , obj->getMetaClass()->getClassName(), regEntry->getRegistryEntryID()); |
546 | #if DEVELOPMENT || DEBUG |
547 | } else if ((noti = OSDynamicCast(IOUserNotification, obj))) { |
548 | // serviceNoti->matching may become NULL if the port gets a no-senders notification, so we have to lock gIOObjectPortLock |
549 | IOLockLock(gIOObjectPortLock); |
550 | serviceNoti = OSDynamicCast(_IOServiceNotifier, noti->userIteratorObject); |
551 | if (serviceNoti && (matching = serviceNoti->matching)) { |
552 | matching->retain(); |
553 | } |
554 | IOLockUnlock(gIOObjectPortLock); |
555 | |
556 | if (matching) { |
557 | s = OSSerialize::withCapacity((unsigned int) page_size); |
558 | if (s && matching->serialize(s)) { |
559 | snprintf(desc, KOBJECT_DESCRIPTION_LENGTH, "%s(%s)" , obj->getMetaClass()->getClassName(), s->text()); |
560 | } |
561 | OSSafeReleaseNULL(s); |
562 | OSSafeReleaseNULL(matching); |
563 | } |
564 | #endif /* DEVELOPMENT || DEBUG */ |
565 | } else { |
566 | snprintf(desc, KOBJECT_DESCRIPTION_LENGTH, "%s" , obj->getMetaClass()->getClassName()); |
567 | } |
568 | } |
569 | |
570 | // FIXME: Implementation of these functions are hidden from the static analyzer. |
571 | // As for now, the analyzer doesn't consistently support wrapper functions |
572 | // for retain and release. |
573 | #ifndef __clang_analyzer__ |
574 | void |
575 | iokit_add_reference( io_object_t obj, natural_t type ) |
576 | { |
577 | if (!obj) { |
578 | return; |
579 | } |
580 | obj->retain(); |
581 | } |
582 | |
583 | void |
584 | iokit_remove_reference( io_object_t obj ) |
585 | { |
586 | if (obj) { |
587 | obj->release(); |
588 | } |
589 | } |
590 | #endif // __clang_analyzer__ |
591 | |
592 | void |
593 | iokit_remove_connect_reference(LIBKERN_CONSUMED io_object_t obj ) |
594 | { |
595 | if (!obj) { |
596 | return; |
597 | } |
598 | obj->release(); |
599 | } |
600 | |
601 | enum { |
602 | kIPCLockNone = 0, |
603 | kIPCLockRead = 1, |
604 | kIPCLockWrite = 2 |
605 | }; |
606 | |
607 | void |
608 | IOUserClient::ipcEnter(int locking) |
609 | { |
610 | switch (locking) { |
611 | case kIPCLockWrite: |
612 | IORWLockWrite(&lock); |
613 | break; |
614 | case kIPCLockRead: |
615 | IORWLockRead(&lock); |
616 | break; |
617 | case kIPCLockNone: |
618 | break; |
619 | default: |
620 | panic("ipcEnter" ); |
621 | } |
622 | |
623 | OSIncrementAtomic(&__ipc); |
624 | } |
625 | |
626 | void |
627 | IOUserClient::ipcExit(int locking) |
628 | { |
629 | bool finalize = false; |
630 | |
631 | assert(__ipc); |
632 | if (1 == OSDecrementAtomic(&__ipc) && isInactive()) { |
633 | IOLockLock(gIOObjectPortLock); |
634 | if ((finalize = __ipcFinal)) { |
635 | __ipcFinal = false; |
636 | } |
637 | IOLockUnlock(gIOObjectPortLock); |
638 | if (finalize) { |
639 | scheduleFinalize(now: true); |
640 | } |
641 | } |
642 | switch (locking) { |
643 | case kIPCLockWrite: |
644 | case kIPCLockRead: |
645 | IORWLockUnlock(&lock); |
646 | break; |
647 | case kIPCLockNone: |
648 | break; |
649 | default: |
650 | panic("ipcExit" ); |
651 | } |
652 | } |
653 | |
654 | void |
655 | iokit_kobject_retain(io_kobject_t machPort) |
656 | { |
657 | assert(OSDynamicCast(IOMachPort, machPort)); |
658 | machPort->retain(); |
659 | } |
660 | |
661 | io_object_t |
662 | iokit_copy_object_for_consumed_kobject(LIBKERN_CONSUMED io_kobject_t machPort, natural_t type) |
663 | { |
664 | io_object_t result; |
665 | |
666 | assert(OSDynamicCast(IOMachPort, machPort)); |
667 | |
668 | IOLockLock(&machPort->lock); |
669 | result = machPort->object; |
670 | if (result) { |
671 | iokit_add_reference(obj: result, type); |
672 | } |
673 | IOLockUnlock(&machPort->lock); |
674 | machPort->release(); |
675 | return result; |
676 | } |
677 | |
678 | bool |
679 | IOUserClient::finalizeUserReferences(OSObject * obj) |
680 | { |
681 | IOUserClient * uc; |
682 | bool ok = true; |
683 | |
684 | if ((uc = OSDynamicCast(IOUserClient, obj))) { |
685 | IOLockLock(gIOObjectPortLock); |
686 | if ((uc->__ipcFinal = (0 != uc->__ipc))) { |
687 | ok = false; |
688 | } |
689 | IOLockUnlock(gIOObjectPortLock); |
690 | } |
691 | return ok; |
692 | } |
693 | |
694 | ipc_port_t |
695 | iokit_port_for_object( io_object_t obj, ipc_kobject_type_t type, ipc_kobject_t * kobj ) |
696 | { |
697 | IOMachPort *machPort = NULL; |
698 | ipc_port_t port = NULL; |
699 | |
700 | IOMachPortHashList *bucket = IOMachPort::bucketForObject(obj, type); |
701 | |
702 | lck_mtx_lock(lck: gIOObjectPortLock); |
703 | |
704 | machPort = IOMachPort::portForObjectInBucket(bucket, obj, type); |
705 | |
706 | if (__improbable(machPort == NULL)) { |
707 | machPort = IOMachPort::withObjectAndType(obj, type); |
708 | if (__improbable(machPort == NULL)) { |
709 | goto end; |
710 | } |
711 | SLIST_INSERT_HEAD(bucket, machPort, link); |
712 | } else { |
713 | machPort->mscount++; |
714 | } |
715 | |
716 | iokit_retain_port(port: machPort->port); |
717 | port = machPort->port; |
718 | |
719 | end: |
720 | if (kobj) { |
721 | *kobj = machPort; |
722 | } |
723 | lck_mtx_unlock(lck: gIOObjectPortLock); |
724 | |
725 | return port; |
726 | } |
727 | |
728 | kern_return_t |
729 | iokit_client_died( io_object_t obj, ipc_port_t /* port */, |
730 | ipc_kobject_type_t type, mach_port_mscount_t * mscount ) |
731 | { |
732 | IOUserClient * client; |
733 | IOMemoryMap * map; |
734 | IOUserNotification * notify; |
735 | IOUserServerCheckInToken * token; |
736 | |
737 | if (!IOMachPort::noMoreSendersForObject( obj, type, mscount )) { |
738 | return kIOReturnNotReady; |
739 | } |
740 | |
741 | switch (type) { |
742 | case IKOT_IOKIT_CONNECT: |
743 | if ((client = OSDynamicCast( IOUserClient, obj ))) { |
744 | IOStatisticsClientCall(); |
745 | IORWLockWrite(&client->lock); |
746 | client->clientDied(); |
747 | IORWLockUnlock(&client->lock); |
748 | } |
749 | break; |
750 | case IKOT_IOKIT_OBJECT: |
751 | if ((map = OSDynamicCast( IOMemoryMap, obj ))) { |
752 | map->taskDied(); |
753 | } else if ((notify = OSDynamicCast( IOUserNotification, obj ))) { |
754 | notify->setNotification( NULL ); |
755 | } |
756 | break; |
757 | case IKOT_IOKIT_IDENT: |
758 | if ((token = OSDynamicCast( IOUserServerCheckInToken, obj ))) { |
759 | token->cancel(); |
760 | } |
761 | break; |
762 | } |
763 | |
764 | return kIOReturnSuccess; |
765 | } |
766 | }; /* extern "C" */ |
767 | |
768 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
769 | |
770 | class IOServiceUserNotification : public IOUserNotification |
771 | { |
772 | OSDeclareDefaultStructors(IOServiceUserNotification); |
773 | |
774 | struct PingMsgKdata { |
775 | mach_msg_header_t msgHdr; |
776 | }; |
777 | struct PingMsgUdata { |
778 | OSNotificationHeader64 ; |
779 | }; |
780 | |
781 | enum { kMaxOutstanding = 1024 }; |
782 | |
783 | ipc_port_t remotePort; |
784 | void *msgReference; |
785 | mach_msg_size_t msgReferenceSize; |
786 | natural_t msgType; |
787 | OSArray * newSet; |
788 | bool armed; |
789 | bool ipcLogged; |
790 | |
791 | public: |
792 | |
793 | virtual bool init( mach_port_t port, natural_t type, |
794 | void * reference, vm_size_t referenceSize, |
795 | bool clientIs64 ); |
796 | virtual void free() APPLE_KEXT_OVERRIDE; |
797 | void invalidatePort(void); |
798 | |
799 | static bool _handler( void * target, |
800 | void * ref, IOService * newService, IONotifier * notifier ); |
801 | virtual bool handler( void * ref, IOService * newService ); |
802 | |
803 | virtual OSObject * getNextObject() APPLE_KEXT_OVERRIDE; |
804 | virtual OSObject * copyNextObject() APPLE_KEXT_OVERRIDE; |
805 | }; |
806 | |
807 | class IOServiceMessageUserNotification : public IOUserNotification |
808 | { |
809 | OSDeclareDefaultStructors(IOServiceMessageUserNotification); |
810 | |
811 | struct PingMsgKdata { |
812 | mach_msg_header_t msgHdr; |
813 | mach_msg_body_t msgBody; |
814 | mach_msg_port_descriptor_t ports[1]; |
815 | }; |
816 | struct PingMsgUdata { |
817 | OSNotificationHeader64 __attribute__ ((packed)); |
818 | }; |
819 | |
820 | ipc_port_t remotePort; |
821 | void *msgReference; |
822 | mach_msg_size_t msgReferenceSize; |
823 | mach_msg_size_t ; |
824 | natural_t msgType; |
825 | uint8_t clientIs64; |
826 | int owningPID; |
827 | bool ipcLogged; |
828 | |
829 | public: |
830 | |
831 | virtual bool init( mach_port_t port, natural_t type, |
832 | void * reference, vm_size_t referenceSize, |
833 | bool clientIs64 ); |
834 | |
835 | virtual void free() APPLE_KEXT_OVERRIDE; |
836 | void invalidatePort(void); |
837 | |
838 | static IOReturn _handler( void * target, void * ref, |
839 | UInt32 messageType, IOService * provider, |
840 | void * messageArgument, vm_size_t argSize ); |
841 | virtual IOReturn handler( void * ref, |
842 | UInt32 messageType, IOService * provider, |
843 | void * messageArgument, vm_size_t argSize ); |
844 | |
845 | virtual OSObject * getNextObject() APPLE_KEXT_OVERRIDE; |
846 | virtual OSObject * copyNextObject() APPLE_KEXT_OVERRIDE; |
847 | }; |
848 | |
849 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
850 | |
851 | #undef super |
852 | #define super IOUserIterator |
853 | OSDefineMetaClass( IOUserNotification, IOUserIterator ); |
854 | OSDefineAbstractStructors( IOUserNotification, IOUserIterator ); |
855 | |
856 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
857 | |
858 | void |
859 | IOUserNotification::free( void ) |
860 | { |
861 | #if DEVELOPMENT || DEBUG |
862 | IOLockLock( gIOObjectPortLock); |
863 | |
864 | assert(userIteratorObject == NULL); |
865 | |
866 | IOLockUnlock( gIOObjectPortLock); |
867 | #endif /* DEVELOPMENT || DEBUG */ |
868 | |
869 | super::free(); |
870 | } |
871 | |
872 | |
873 | void |
874 | IOUserNotification::setNotification( IONotifier * notify ) |
875 | { |
876 | OSObject * previousNotify; |
877 | |
878 | /* |
879 | * We must retain this object here before proceeding. |
880 | * Two threads may race in setNotification(). If one thread sets a new notifier while the |
881 | * other thread sets the notifier to NULL, it is possible for the second thread to call release() |
882 | * before the first thread calls retain(). Without the retain here, this thread interleaving |
883 | * would cause the object to get released and freed before it is retained by the first thread, |
884 | * which is a UaF. |
885 | */ |
886 | retain(); |
887 | |
888 | IOLockLock( gIOObjectPortLock); |
889 | |
890 | previousNotify = userIteratorObject; |
891 | userIteratorObject = notify; |
892 | |
893 | IOLockUnlock( gIOObjectPortLock); |
894 | |
895 | if (previousNotify) { |
896 | assert(OSDynamicCast(IONotifier, previousNotify)); |
897 | ((IONotifier *)previousNotify)->remove(); |
898 | |
899 | if (notify == NULL) { |
900 | release(); |
901 | } |
902 | } else if (notify) { |
903 | // new IONotifier, retain the object. release() will happen in setNotification(NULL) |
904 | retain(); |
905 | } |
906 | |
907 | release(); // paired with retain() at beginning of this method |
908 | } |
909 | |
910 | void |
911 | IOUserNotification::reset() |
912 | { |
913 | // ? |
914 | } |
915 | |
916 | bool |
917 | IOUserNotification::isValid() |
918 | { |
919 | return true; |
920 | } |
921 | |
922 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
923 | |
924 | #undef super |
925 | #define super IOUserNotification |
926 | OSDefineMetaClassAndStructors(IOServiceUserNotification, IOUserNotification) |
927 | |
928 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
929 | |
930 | bool |
931 | IOServiceUserNotification::init( mach_port_t port, natural_t type, |
932 | void * reference, vm_size_t referenceSize, |
933 | bool clientIs64 ) |
934 | { |
935 | if (!super::init()) { |
936 | return false; |
937 | } |
938 | |
939 | newSet = OSArray::withCapacity( capacity: 1 ); |
940 | if (!newSet) { |
941 | return false; |
942 | } |
943 | |
944 | if (referenceSize > sizeof(OSAsyncReference64)) { |
945 | return false; |
946 | } |
947 | |
948 | msgReferenceSize = mach_round_msg(x: (mach_msg_size_t)referenceSize); |
949 | msgReference = IOMallocZeroData(msgReferenceSize); |
950 | if (!msgReference) { |
951 | return false; |
952 | } |
953 | |
954 | remotePort = port; |
955 | msgType = type; |
956 | bcopy( src: reference, dst: msgReference, n: referenceSize ); |
957 | |
958 | return true; |
959 | } |
960 | |
961 | void |
962 | IOServiceUserNotification::invalidatePort(void) |
963 | { |
964 | remotePort = MACH_PORT_NULL; |
965 | } |
966 | |
967 | void |
968 | IOServiceUserNotification::free( void ) |
969 | { |
970 | if (remotePort) { |
971 | iokit_release_port_send(port: remotePort); |
972 | } |
973 | IOFreeData(address: msgReference, size: msgReferenceSize); |
974 | OSSafeReleaseNULL(newSet); |
975 | |
976 | super::free(); |
977 | } |
978 | |
979 | bool |
980 | IOServiceUserNotification::_handler( void * target, |
981 | void * ref, IOService * newService, IONotifier * notifier ) |
982 | { |
983 | IOServiceUserNotification * targetObj = (IOServiceUserNotification *)target; |
984 | bool ret; |
985 | |
986 | targetObj->retain(); |
987 | ret = targetObj->handler( ref, newService ); |
988 | targetObj->release(); |
989 | return ret; |
990 | } |
991 | |
992 | bool |
993 | IOServiceUserNotification::handler( void * ref, |
994 | IOService * newService ) |
995 | { |
996 | unsigned int count; |
997 | kern_return_t kr; |
998 | ipc_port_t port = NULL; |
999 | bool sendPing = false; |
1000 | mach_msg_size_t msgSize, payloadSize; |
1001 | |
1002 | IOTakeLock( lock: &lock ); |
1003 | |
1004 | count = newSet->getCount(); |
1005 | if (count < kMaxOutstanding) { |
1006 | newSet->setObject( newService ); |
1007 | if ((sendPing = (armed && (0 == count)))) { |
1008 | armed = false; |
1009 | } |
1010 | } |
1011 | |
1012 | IOUnlock( lock: &lock ); |
1013 | |
1014 | if (kIOServiceTerminatedNotificationType == msgType) { |
1015 | lck_mtx_lock(lck: gIOObjectPortLock); |
1016 | newService->setMachPortHoldDestroy(true); |
1017 | lck_mtx_unlock(lck: gIOObjectPortLock); |
1018 | } |
1019 | |
1020 | if (sendPing) { |
1021 | port = iokit_port_for_object( obj: this, type: IKOT_IOKIT_OBJECT, NULL ); |
1022 | |
1023 | payloadSize = sizeof(PingMsgUdata) - sizeof(OSAsyncReference64) + msgReferenceSize; |
1024 | msgSize = (mach_msg_size_t)(sizeof(PingMsgKdata) + payloadSize); |
1025 | |
1026 | kr = kernel_mach_msg_send_with_builder_internal(desc_count: 0, payload_size: payloadSize, |
1027 | option: (MACH_SEND_MSG | MACH_SEND_ALWAYS | MACH_SEND_IMPORTANCE), |
1028 | MACH_MSG_TIMEOUT_NONE, NULL, |
1029 | builder: ^(mach_msg_header_t *hdr, __assert_only mach_msg_descriptor_t *descs, void *payload){ |
1030 | PingMsgUdata *udata = (PingMsgUdata *)payload; |
1031 | |
1032 | hdr->msgh_remote_port = remotePort; |
1033 | hdr->msgh_local_port = port; |
1034 | hdr->msgh_bits = MACH_MSGH_BITS( |
1035 | MACH_MSG_TYPE_COPY_SEND /*remote*/, |
1036 | MACH_MSG_TYPE_MAKE_SEND /*local*/); |
1037 | hdr->msgh_size = msgSize; |
1038 | hdr->msgh_id = kOSNotificationMessageID; |
1039 | |
1040 | assert(descs == NULL); |
1041 | /* End of kernel processed data */ |
1042 | |
1043 | udata->notifyHeader.size = 0; |
1044 | udata->notifyHeader.type = msgType; |
1045 | |
1046 | assert((char *)udata->notifyHeader.reference + msgReferenceSize <= (char *)payload + payloadSize); |
1047 | bcopy( src: msgReference, dst: udata->notifyHeader.reference, n: msgReferenceSize ); |
1048 | }); |
1049 | |
1050 | if (port) { |
1051 | iokit_release_port( port ); |
1052 | } |
1053 | |
1054 | if ((KERN_SUCCESS != kr) && !ipcLogged) { |
1055 | ipcLogged = true; |
1056 | IOLog(format: "%s: kernel_mach_msg_send (0x%x)\n" , __PRETTY_FUNCTION__, kr ); |
1057 | } |
1058 | } |
1059 | |
1060 | return true; |
1061 | } |
1062 | OSObject * |
1063 | IOServiceUserNotification::getNextObject() |
1064 | { |
1065 | assert(false); |
1066 | return NULL; |
1067 | } |
1068 | |
1069 | OSObject * |
1070 | IOServiceUserNotification::copyNextObject() |
1071 | { |
1072 | unsigned int count; |
1073 | OSObject * result; |
1074 | |
1075 | IOLockLock(&lock); |
1076 | |
1077 | count = newSet->getCount(); |
1078 | if (count) { |
1079 | result = newSet->getObject( index: count - 1 ); |
1080 | result->retain(); |
1081 | newSet->removeObject( index: count - 1); |
1082 | } else { |
1083 | result = NULL; |
1084 | armed = true; |
1085 | } |
1086 | |
1087 | IOLockUnlock(&lock); |
1088 | |
1089 | return result; |
1090 | } |
1091 | |
1092 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
1093 | |
1094 | OSDefineMetaClassAndStructors(IOServiceMessageUserNotification, IOUserNotification) |
1095 | |
1096 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
1097 | |
1098 | bool |
1099 | IOServiceMessageUserNotification::init( mach_port_t port, natural_t type, |
1100 | void * reference, vm_size_t referenceSize, bool client64 ) |
1101 | { |
1102 | if (!super::init()) { |
1103 | return false; |
1104 | } |
1105 | |
1106 | if (referenceSize > sizeof(OSAsyncReference64)) { |
1107 | return false; |
1108 | } |
1109 | |
1110 | clientIs64 = client64; |
1111 | |
1112 | owningPID = proc_selfpid(); |
1113 | |
1114 | msgReferenceSize = mach_round_msg(x: (mach_msg_size_t)referenceSize); |
1115 | msgReference = IOMallocZeroData(msgReferenceSize); |
1116 | if (!msgReference) { |
1117 | return false; |
1118 | } |
1119 | |
1120 | remotePort = port; |
1121 | msgType = type; |
1122 | bcopy( src: reference, dst: msgReference, n: referenceSize ); |
1123 | |
1124 | return true; |
1125 | } |
1126 | |
1127 | void |
1128 | IOServiceMessageUserNotification::invalidatePort(void) |
1129 | { |
1130 | remotePort = MACH_PORT_NULL; |
1131 | } |
1132 | |
1133 | void |
1134 | IOServiceMessageUserNotification::free( void ) |
1135 | { |
1136 | if (remotePort) { |
1137 | iokit_release_port_send(port: remotePort); |
1138 | } |
1139 | IOFreeData(address: msgReference, size: msgReferenceSize); |
1140 | |
1141 | super::free(); |
1142 | } |
1143 | |
1144 | IOReturn |
1145 | IOServiceMessageUserNotification::_handler( void * target, void * ref, |
1146 | UInt32 messageType, IOService * provider, |
1147 | void * argument, vm_size_t argSize ) |
1148 | { |
1149 | IOServiceMessageUserNotification * targetObj = (IOServiceMessageUserNotification *)target; |
1150 | IOReturn ret; |
1151 | |
1152 | targetObj->retain(); |
1153 | ret = targetObj->handler( |
1154 | ref, messageType, provider, messageArgument: argument, argSize); |
1155 | targetObj->release(); |
1156 | return ret; |
1157 | } |
1158 | |
1159 | IOReturn |
1160 | IOServiceMessageUserNotification::handler( void * ref, |
1161 | UInt32 messageType, IOService * provider, |
1162 | void * messageArgument, vm_size_t callerArgSize ) |
1163 | { |
1164 | kern_return_t kr; |
1165 | vm_size_t argSize; |
1166 | mach_msg_size_t thisMsgSize; |
1167 | ipc_port_t thisPort, providerPort; |
1168 | |
1169 | if (kIOMessageCopyClientID == messageType) { |
1170 | *((void **) messageArgument) = OSNumber::withNumber(value: owningPID, numberOfBits: 32); |
1171 | return kIOReturnSuccess; |
1172 | } |
1173 | |
1174 | if (callerArgSize == 0) { |
1175 | if (clientIs64) { |
1176 | argSize = sizeof(io_user_reference_t); |
1177 | } else { |
1178 | argSize = sizeof(uint32_t); |
1179 | } |
1180 | } else { |
1181 | if (callerArgSize > kIOUserNotifyMaxMessageSize) { |
1182 | callerArgSize = kIOUserNotifyMaxMessageSize; |
1183 | } |
1184 | argSize = callerArgSize; |
1185 | } |
1186 | |
1187 | // adjust message size for ipc restrictions |
1188 | natural_t type = msgType; |
1189 | type &= ~(kIOKitNoticationMsgSizeMask << kIOKitNoticationTypeSizeAdjShift); |
1190 | type |= ((argSize & kIOKitNoticationMsgSizeMask) << kIOKitNoticationTypeSizeAdjShift); |
1191 | argSize = (argSize + kIOKitNoticationMsgSizeMask) & ~kIOKitNoticationMsgSizeMask; |
1192 | |
1193 | mach_msg_size_t = kIOUserNotifyMaxMessageSize + sizeof(IOServiceInterestContent64); |
1194 | mach_msg_size_t msgSize = (mach_msg_size_t) (sizeof(PingMsgKdata) + |
1195 | sizeof(PingMsgUdata) - sizeof(OSAsyncReference64) + msgReferenceSize); |
1196 | |
1197 | if (os_add3_overflow(msgSize, offsetof(IOServiceInterestContent64, messageArgument), argSize, &thisMsgSize)) { |
1198 | return kIOReturnBadArgument; |
1199 | } |
1200 | mach_msg_size_t payloadSize = thisMsgSize - sizeof(PingMsgKdata); |
1201 | |
1202 | providerPort = iokit_port_for_object( obj: provider, type: IKOT_IOKIT_OBJECT, NULL ); |
1203 | thisPort = iokit_port_for_object( obj: this, type: IKOT_IOKIT_OBJECT, NULL ); |
1204 | |
1205 | kr = kernel_mach_msg_send_with_builder_internal(desc_count: 1, payload_size: payloadSize, |
1206 | option: (MACH_SEND_MSG | MACH_SEND_ALWAYS | MACH_SEND_IMPORTANCE), |
1207 | MACH_MSG_TIMEOUT_NONE, NULL, |
1208 | builder: ^(mach_msg_header_t *hdr, mach_msg_descriptor_t *descs, void *payload){ |
1209 | mach_msg_port_descriptor_t *port_desc = (mach_msg_port_descriptor_t *)descs; |
1210 | PingMsgUdata *udata = (PingMsgUdata *)payload; |
1211 | IOServiceInterestContent64 * data; |
1212 | mach_msg_size_t dataOffset; |
1213 | |
1214 | hdr->msgh_remote_port = remotePort; |
1215 | hdr->msgh_local_port = thisPort; |
1216 | hdr->msgh_bits = MACH_MSGH_BITS_COMPLEX |
1217 | | MACH_MSGH_BITS( |
1218 | MACH_MSG_TYPE_COPY_SEND /*remote*/, |
1219 | MACH_MSG_TYPE_MAKE_SEND /*local*/); |
1220 | hdr->msgh_size = thisMsgSize; |
1221 | hdr->msgh_id = kOSNotificationMessageID; |
1222 | |
1223 | /* body.msgh_descriptor_count is set automatically after the closure */ |
1224 | |
1225 | port_desc[0].name = providerPort; |
1226 | port_desc[0].disposition = MACH_MSG_TYPE_MAKE_SEND; |
1227 | port_desc[0].type = MACH_MSG_PORT_DESCRIPTOR; |
1228 | /* End of kernel processed data */ |
1229 | |
1230 | udata->notifyHeader.size = extraSize; |
1231 | udata->notifyHeader.type = type; |
1232 | bcopy( src: msgReference, dst: udata->notifyHeader.reference, n: msgReferenceSize ); |
1233 | |
1234 | /* data is after msgReference */ |
1235 | dataOffset = sizeof(PingMsgUdata) - sizeof(OSAsyncReference64) + msgReferenceSize; |
1236 | data = (IOServiceInterestContent64 *) (((uint8_t *) udata) + dataOffset); |
1237 | data->messageType = messageType; |
1238 | |
1239 | if (callerArgSize == 0) { |
1240 | assert((char *)data->messageArgument + argSize <= (char *)payload + payloadSize); |
1241 | data->messageArgument[0] = (io_user_reference_t) messageArgument; |
1242 | if (!clientIs64) { |
1243 | data->messageArgument[0] |= (data->messageArgument[0] << 32); |
1244 | } |
1245 | } else { |
1246 | assert((char *)data->messageArgument + callerArgSize <= (char *)payload + payloadSize); |
1247 | bcopy(src: messageArgument, dst: data->messageArgument, n: callerArgSize); |
1248 | } |
1249 | }); |
1250 | |
1251 | if (thisPort) { |
1252 | iokit_release_port( port: thisPort ); |
1253 | } |
1254 | if (providerPort) { |
1255 | iokit_release_port( port: providerPort ); |
1256 | } |
1257 | |
1258 | if (kr == MACH_SEND_NO_BUFFER) { |
1259 | return kIOReturnNoMemory; |
1260 | } |
1261 | |
1262 | if ((KERN_SUCCESS != kr) && !ipcLogged) { |
1263 | ipcLogged = true; |
1264 | IOLog(format: "%s: kernel_mach_msg_send (0x%x)\n" , __PRETTY_FUNCTION__, kr ); |
1265 | } |
1266 | |
1267 | return kIOReturnSuccess; |
1268 | } |
1269 | |
1270 | OSObject * |
1271 | IOServiceMessageUserNotification::getNextObject() |
1272 | { |
1273 | return NULL; |
1274 | } |
1275 | |
1276 | OSObject * |
1277 | IOServiceMessageUserNotification::copyNextObject() |
1278 | { |
1279 | return NULL; |
1280 | } |
1281 | |
1282 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
1283 | |
1284 | #undef super |
1285 | #define super IOService |
1286 | OSDefineMetaClassAndAbstractStructors( IOUserClient, IOService ) |
1287 | |
1288 | IOLock * gIOUserClientOwnersLock; |
1289 | |
1290 | static_assert(offsetof(IOUserClient, __opaque_end) - |
1291 | offsetof(IOUserClient, __opaque_start) == sizeof(void *) * 9, |
1292 | "ABI check: Opaque ivars for IOUserClient must be 9 void * big" ); |
1293 | |
1294 | void |
1295 | IOUserClient::initialize( void ) |
1296 | { |
1297 | gIOObjectPortLock = IOLockAlloc(); |
1298 | gIOUserClientOwnersLock = IOLockAlloc(); |
1299 | gIOUserServerLock = IOLockAlloc(); |
1300 | assert(gIOObjectPortLock && gIOUserClientOwnersLock); |
1301 | |
1302 | #if IOTRACKING |
1303 | IOTrackingQueueCollectUser(IOUserIterator::gMetaClass.getTracking()); |
1304 | IOTrackingQueueCollectUser(IOServiceMessageUserNotification::gMetaClass.getTracking()); |
1305 | IOTrackingQueueCollectUser(IOServiceUserNotification::gMetaClass.getTracking()); |
1306 | IOTrackingQueueCollectUser(IOUserClient::gMetaClass.getTracking()); |
1307 | IOTrackingQueueCollectUser(IOMachPort::gMetaClass.getTracking()); |
1308 | #endif /* IOTRACKING */ |
1309 | } |
1310 | |
1311 | void |
1312 | #if __LP64__ |
1313 | __attribute__((__noreturn__)) |
1314 | #endif |
1315 | IOUserClient::setAsyncReference(OSAsyncReference asyncRef, |
1316 | mach_port_t wakePort, |
1317 | void *callback, void *refcon) |
1318 | { |
1319 | #if __LP64__ |
1320 | panic("setAsyncReference not valid for 64b" ); |
1321 | #else |
1322 | asyncRef[kIOAsyncReservedIndex] = ((uintptr_t) wakePort) |
1323 | | (kIOUCAsync0Flags & asyncRef[kIOAsyncReservedIndex]); |
1324 | asyncRef[kIOAsyncCalloutFuncIndex] = (uintptr_t) callback; |
1325 | asyncRef[kIOAsyncCalloutRefconIndex] = (uintptr_t) refcon; |
1326 | #endif |
1327 | } |
1328 | |
1329 | void |
1330 | IOUserClient::setAsyncReference64(OSAsyncReference64 asyncRef, |
1331 | mach_port_t wakePort, |
1332 | mach_vm_address_t callback, io_user_reference_t refcon) |
1333 | { |
1334 | asyncRef[kIOAsyncReservedIndex] = ((io_user_reference_t) wakePort) |
1335 | | (kIOUCAsync0Flags & asyncRef[kIOAsyncReservedIndex]); |
1336 | asyncRef[kIOAsyncCalloutFuncIndex] = (io_user_reference_t) callback; |
1337 | asyncRef[kIOAsyncCalloutRefconIndex] = refcon; |
1338 | } |
1339 | |
1340 | void |
1341 | IOUserClient::setAsyncReference64(OSAsyncReference64 asyncRef, |
1342 | mach_port_t wakePort, |
1343 | mach_vm_address_t callback, io_user_reference_t refcon, task_t task) |
1344 | { |
1345 | setAsyncReference64(asyncRef, wakePort, callback, refcon); |
1346 | if (vm_map_is_64bit(map: get_task_map(task))) { |
1347 | asyncRef[kIOAsyncReservedIndex] |= kIOUCAsync64Flag; |
1348 | } |
1349 | } |
1350 | |
1351 | static OSDictionary * |
1352 | CopyConsoleUser(UInt32 uid) |
1353 | { |
1354 | OSArray * array; |
1355 | OSDictionary * user = NULL; |
1356 | |
1357 | OSObject * ioProperty = IORegistryEntry::getRegistryRoot()->copyProperty(aKey: gIOConsoleUsersKey); |
1358 | if ((array = OSDynamicCast(OSArray, ioProperty))) { |
1359 | for (unsigned int idx = 0; |
1360 | (user = OSDynamicCast(OSDictionary, array->getObject(idx))); |
1361 | idx++) { |
1362 | OSNumber * num; |
1363 | |
1364 | if ((num = OSDynamicCast(OSNumber, user->getObject(gIOConsoleSessionUIDKey))) |
1365 | && (uid == num->unsigned32BitValue())) { |
1366 | user->retain(); |
1367 | break; |
1368 | } |
1369 | } |
1370 | } |
1371 | OSSafeReleaseNULL(ioProperty); |
1372 | return user; |
1373 | } |
1374 | |
1375 | static OSDictionary * |
1376 | CopyUserOnConsole(void) |
1377 | { |
1378 | OSArray * array; |
1379 | OSDictionary * user = NULL; |
1380 | |
1381 | OSObject * ioProperty = IORegistryEntry::getRegistryRoot()->copyProperty(aKey: gIOConsoleUsersKey); |
1382 | if ((array = OSDynamicCast(OSArray, ioProperty))) { |
1383 | for (unsigned int idx = 0; |
1384 | (user = OSDynamicCast(OSDictionary, array->getObject(idx))); |
1385 | idx++) { |
1386 | if (kOSBooleanTrue == user->getObject(aKey: gIOConsoleSessionOnConsoleKey)) { |
1387 | user->retain(); |
1388 | break; |
1389 | } |
1390 | } |
1391 | } |
1392 | OSSafeReleaseNULL(ioProperty); |
1393 | return user; |
1394 | } |
1395 | |
1396 | IOReturn |
1397 | IOUserClient::clientHasAuthorization( task_t task, |
1398 | IOService * service ) |
1399 | { |
1400 | proc_t p; |
1401 | |
1402 | p = (proc_t) get_bsdtask_info(task); |
1403 | if (p) { |
1404 | uint64_t authorizationID; |
1405 | |
1406 | authorizationID = proc_uniqueid(p); |
1407 | if (authorizationID) { |
1408 | if (service->getAuthorizationID() == authorizationID) { |
1409 | return kIOReturnSuccess; |
1410 | } |
1411 | } |
1412 | } |
1413 | |
1414 | return kIOReturnNotPermitted; |
1415 | } |
1416 | |
1417 | IOReturn |
1418 | IOUserClient::clientHasPrivilege( void * securityToken, |
1419 | const char * privilegeName ) |
1420 | { |
1421 | kern_return_t kr; |
1422 | security_token_t token; |
1423 | mach_msg_type_number_t count; |
1424 | task_t task; |
1425 | OSDictionary * user; |
1426 | bool secureConsole; |
1427 | |
1428 | |
1429 | if (!strncmp(s1: privilegeName, kIOClientPrivilegeForeground, |
1430 | n: sizeof(kIOClientPrivilegeForeground))) { |
1431 | if (task_is_gpu_denied(task: current_task())) { |
1432 | return kIOReturnNotPrivileged; |
1433 | } else { |
1434 | return kIOReturnSuccess; |
1435 | } |
1436 | } |
1437 | |
1438 | if (!strncmp(s1: privilegeName, kIOClientPrivilegeConsoleSession, |
1439 | n: sizeof(kIOClientPrivilegeConsoleSession))) { |
1440 | kauth_cred_t cred; |
1441 | proc_t p; |
1442 | |
1443 | task = (task_t) securityToken; |
1444 | if (!task) { |
1445 | task = current_task(); |
1446 | } |
1447 | p = (proc_t) get_bsdtask_info(task); |
1448 | kr = kIOReturnNotPrivileged; |
1449 | |
1450 | if (p && (cred = kauth_cred_proc_ref(procp: p))) { |
1451 | user = CopyUserOnConsole(); |
1452 | if (user) { |
1453 | OSNumber * num; |
1454 | if ((num = OSDynamicCast(OSNumber, user->getObject(gIOConsoleSessionAuditIDKey))) |
1455 | && (cred->cr_audit.as_aia_p->ai_asid == (au_asid_t) num->unsigned32BitValue())) { |
1456 | kr = kIOReturnSuccess; |
1457 | } |
1458 | user->release(); |
1459 | } |
1460 | kauth_cred_unref(&cred); |
1461 | } |
1462 | return kr; |
1463 | } |
1464 | |
1465 | if ((secureConsole = !strncmp(s1: privilegeName, kIOClientPrivilegeSecureConsoleProcess, |
1466 | n: sizeof(kIOClientPrivilegeSecureConsoleProcess)))) { |
1467 | task = (task_t)((IOUCProcessToken *)securityToken)->token; |
1468 | } else { |
1469 | task = (task_t)securityToken; |
1470 | } |
1471 | |
1472 | count = TASK_SECURITY_TOKEN_COUNT; |
1473 | kr = task_info( target_task: task, TASK_SECURITY_TOKEN, task_info_out: (task_info_t) &token, task_info_outCnt: &count ); |
1474 | |
1475 | if (KERN_SUCCESS != kr) { |
1476 | } else if (!strncmp(s1: privilegeName, kIOClientPrivilegeAdministrator, |
1477 | n: sizeof(kIOClientPrivilegeAdministrator))) { |
1478 | if (0 != token.val[0]) { |
1479 | kr = kIOReturnNotPrivileged; |
1480 | } |
1481 | } else if (!strncmp(s1: privilegeName, kIOClientPrivilegeLocalUser, |
1482 | n: sizeof(kIOClientPrivilegeLocalUser))) { |
1483 | user = CopyConsoleUser(uid: token.val[0]); |
1484 | if (user) { |
1485 | user->release(); |
1486 | } else { |
1487 | kr = kIOReturnNotPrivileged; |
1488 | } |
1489 | } else if (secureConsole || !strncmp(s1: privilegeName, kIOClientPrivilegeConsoleUser, |
1490 | n: sizeof(kIOClientPrivilegeConsoleUser))) { |
1491 | user = CopyConsoleUser(uid: token.val[0]); |
1492 | if (user) { |
1493 | if (user->getObject(aKey: gIOConsoleSessionOnConsoleKey) != kOSBooleanTrue) { |
1494 | kr = kIOReturnNotPrivileged; |
1495 | } else if (secureConsole) { |
1496 | OSNumber * pid = OSDynamicCast(OSNumber, user->getObject(gIOConsoleSessionSecureInputPIDKey)); |
1497 | if (pid && pid->unsigned32BitValue() != ((IOUCProcessToken *)securityToken)->pid) { |
1498 | kr = kIOReturnNotPrivileged; |
1499 | } |
1500 | } |
1501 | user->release(); |
1502 | } else { |
1503 | kr = kIOReturnNotPrivileged; |
1504 | } |
1505 | } else { |
1506 | kr = kIOReturnUnsupported; |
1507 | } |
1508 | |
1509 | return kr; |
1510 | } |
1511 | |
1512 | OSDictionary * |
1513 | IOUserClient::copyClientEntitlements(task_t task) |
1514 | { |
1515 | proc_t p = NULL; |
1516 | pid_t pid = 0; |
1517 | OSDictionary *entitlements = NULL; |
1518 | |
1519 | p = (proc_t)get_bsdtask_info(task); |
1520 | if (p == NULL) { |
1521 | return NULL; |
1522 | } |
1523 | pid = proc_pid(p); |
1524 | |
1525 | if (cs_entitlements_dictionary_copy(p, (void **)&entitlements) == 0) { |
1526 | if (entitlements) { |
1527 | return entitlements; |
1528 | } |
1529 | } |
1530 | |
1531 | // If the above fails, thats it |
1532 | return NULL; |
1533 | } |
1534 | |
1535 | OSDictionary * |
1536 | IOUserClient::copyClientEntitlementsVnode(vnode_t vnode, off_t offset) |
1537 | { |
1538 | OSDictionary *entitlements = NULL; |
1539 | |
1540 | if (cs_entitlements_dictionary_copy_vnode(vnode, offset, (void**)&entitlements) != 0) { |
1541 | return NULL; |
1542 | } |
1543 | return entitlements; |
1544 | } |
1545 | |
1546 | OSObject * |
1547 | IOUserClient::copyClientEntitlement( task_t task, |
1548 | const char * entitlement ) |
1549 | { |
1550 | void *entitlement_object = NULL; |
1551 | |
1552 | if (task == NULL) { |
1553 | task = current_task(); |
1554 | } |
1555 | |
1556 | /* Validate input arguments */ |
1557 | if (task == kernel_task || entitlement == NULL) { |
1558 | return NULL; |
1559 | } |
1560 | proc_t proc = (proc_t)get_bsdtask_info(task); |
1561 | |
1562 | kern_return_t ret = amfi->OSEntitlements.copyEntitlementAsOSObjectWithProc( |
1563 | proc, |
1564 | entitlement, |
1565 | &entitlement_object); |
1566 | |
1567 | if (ret != KERN_SUCCESS) { |
1568 | return NULL; |
1569 | } |
1570 | assert(entitlement_object != NULL); |
1571 | |
1572 | return (OSObject*)entitlement_object; |
1573 | } |
1574 | |
1575 | OSObject * |
1576 | IOUserClient::copyClientEntitlementVnode( |
1577 | struct vnode *vnode, |
1578 | off_t offset, |
1579 | const char *entitlement) |
1580 | { |
1581 | OSDictionary *entitlements; |
1582 | OSObject *value; |
1583 | |
1584 | entitlements = copyClientEntitlementsVnode(vnode, offset); |
1585 | if (entitlements == NULL) { |
1586 | return NULL; |
1587 | } |
1588 | |
1589 | /* Fetch the entitlement value from the dictionary. */ |
1590 | value = entitlements->getObject(aKey: entitlement); |
1591 | if (value != NULL) { |
1592 | value->retain(); |
1593 | } |
1594 | |
1595 | entitlements->release(); |
1596 | return value; |
1597 | } |
1598 | |
1599 | bool |
1600 | IOUserClient::init() |
1601 | { |
1602 | if (getPropertyTable() || super::init()) { |
1603 | return reserve(); |
1604 | } |
1605 | |
1606 | return false; |
1607 | } |
1608 | |
1609 | bool |
1610 | IOUserClient::init(OSDictionary * dictionary) |
1611 | { |
1612 | if (getPropertyTable() || super::init(dictionary)) { |
1613 | return reserve(); |
1614 | } |
1615 | |
1616 | return false; |
1617 | } |
1618 | |
1619 | bool |
1620 | IOUserClient::initWithTask(task_t owningTask, |
1621 | void * securityID, |
1622 | UInt32 type ) |
1623 | { |
1624 | if (getPropertyTable() || super::init()) { |
1625 | return reserve(); |
1626 | } |
1627 | |
1628 | return false; |
1629 | } |
1630 | |
1631 | bool |
1632 | IOUserClient::initWithTask(task_t owningTask, |
1633 | void * securityID, |
1634 | UInt32 type, |
1635 | OSDictionary * properties ) |
1636 | { |
1637 | bool ok; |
1638 | |
1639 | ok = super::init( dictionary: properties ); |
1640 | ok &= initWithTask( owningTask, securityID, type ); |
1641 | |
1642 | return ok; |
1643 | } |
1644 | |
1645 | bool |
1646 | IOUserClient::reserve() |
1647 | { |
1648 | if (!reserved) { |
1649 | reserved = IOMallocType(ExpansionData); |
1650 | } |
1651 | setTerminateDefer(NULL, defer: true); |
1652 | IOStatisticsRegisterCounter(); |
1653 | IORWLockInlineInit(&lock); |
1654 | IOLockInlineInit(&filterLock); |
1655 | |
1656 | return true; |
1657 | } |
1658 | |
1659 | struct IOUserClientOwner { |
1660 | task_t task; |
1661 | queue_chain_t taskLink; |
1662 | IOUserClient * uc; |
1663 | queue_chain_t ucLink; |
1664 | }; |
1665 | |
1666 | IOReturn |
1667 | IOUserClient::registerOwner(task_t task) |
1668 | { |
1669 | IOUserClientOwner * owner; |
1670 | IOReturn ret; |
1671 | bool newOwner; |
1672 | |
1673 | IOLockLock(gIOUserClientOwnersLock); |
1674 | |
1675 | newOwner = true; |
1676 | ret = kIOReturnSuccess; |
1677 | |
1678 | if (!owners.next) { |
1679 | queue_init(&owners); |
1680 | } else { |
1681 | queue_iterate(&owners, owner, IOUserClientOwner *, ucLink) |
1682 | { |
1683 | if (task != owner->task) { |
1684 | continue; |
1685 | } |
1686 | newOwner = false; |
1687 | break; |
1688 | } |
1689 | } |
1690 | if (newOwner) { |
1691 | owner = IOMallocType(IOUserClientOwner); |
1692 | |
1693 | owner->task = task; |
1694 | owner->uc = this; |
1695 | queue_enter_first(&owners, owner, IOUserClientOwner *, ucLink); |
1696 | queue_enter_first(task_io_user_clients(task), owner, IOUserClientOwner *, taskLink); |
1697 | if (messageAppSuspended) { |
1698 | task_set_message_app_suspended(task, enable: true); |
1699 | } |
1700 | } |
1701 | |
1702 | IOLockUnlock(gIOUserClientOwnersLock); |
1703 | |
1704 | return ret; |
1705 | } |
1706 | |
1707 | void |
1708 | IOUserClient::noMoreSenders(void) |
1709 | { |
1710 | IOUserClientOwner * owner; |
1711 | IOUserClientOwner * iter; |
1712 | queue_head_t * taskque; |
1713 | bool hasMessageAppSuspended; |
1714 | |
1715 | IOLockLock(gIOUserClientOwnersLock); |
1716 | |
1717 | if (owners.next) { |
1718 | while (!queue_empty(&owners)) { |
1719 | owner = (IOUserClientOwner *)(void *) queue_first(&owners); |
1720 | taskque = task_io_user_clients(task: owner->task); |
1721 | queue_remove(taskque, owner, IOUserClientOwner *, taskLink); |
1722 | hasMessageAppSuspended = false; |
1723 | queue_iterate(taskque, iter, IOUserClientOwner *, taskLink) { |
1724 | hasMessageAppSuspended = iter->uc->messageAppSuspended; |
1725 | if (hasMessageAppSuspended) { |
1726 | break; |
1727 | } |
1728 | } |
1729 | task_set_message_app_suspended(task: owner->task, enable: hasMessageAppSuspended); |
1730 | queue_remove(&owners, owner, IOUserClientOwner *, ucLink); |
1731 | IOFreeType(owner, IOUserClientOwner); |
1732 | } |
1733 | owners.next = owners.prev = NULL; |
1734 | } |
1735 | |
1736 | IOLockUnlock(gIOUserClientOwnersLock); |
1737 | } |
1738 | |
1739 | |
1740 | extern "C" void |
1741 | iokit_task_app_suspended_changed(task_t task) |
1742 | { |
1743 | queue_head_t * taskque; |
1744 | IOUserClientOwner * owner; |
1745 | OSSet * set; |
1746 | |
1747 | IOLockLock(gIOUserClientOwnersLock); |
1748 | |
1749 | taskque = task_io_user_clients(task); |
1750 | set = NULL; |
1751 | queue_iterate(taskque, owner, IOUserClientOwner *, taskLink) { |
1752 | if (!owner->uc->messageAppSuspended) { |
1753 | continue; |
1754 | } |
1755 | if (!set) { |
1756 | set = OSSet::withCapacity(capacity: 4); |
1757 | if (!set) { |
1758 | break; |
1759 | } |
1760 | } |
1761 | set->setObject(owner->uc); |
1762 | } |
1763 | |
1764 | IOLockUnlock(gIOUserClientOwnersLock); |
1765 | |
1766 | if (set) { |
1767 | set->iterateObjects(block: ^bool (OSObject * obj) { |
1768 | IOUserClient * uc; |
1769 | |
1770 | uc = (typeof(uc))obj; |
1771 | #if 0 |
1772 | { |
1773 | OSString * str; |
1774 | str = IOCopyLogNameForPID(task_pid(task)); |
1775 | IOLog("iokit_task_app_suspended_changed(%s) %s %d\n" , str ? str->getCStringNoCopy() : "" , |
1776 | uc->getName(), task_is_app_suspended(task)); |
1777 | OSSafeReleaseNULL(str); |
1778 | } |
1779 | #endif |
1780 | uc->message(kIOMessageTaskAppSuspendedChange, NULL); |
1781 | |
1782 | return false; |
1783 | }); |
1784 | set->release(); |
1785 | } |
1786 | } |
1787 | |
1788 | static kern_return_t |
1789 | iokit_task_terminate_phase1(task_t task) |
1790 | { |
1791 | queue_head_t * taskque; |
1792 | IOUserClientOwner * iter; |
1793 | OSSet * userServers = NULL; |
1794 | |
1795 | if (!task_is_driver(task)) { |
1796 | return KERN_SUCCESS; |
1797 | } |
1798 | userServers = OSSet::withCapacity(capacity: 1); |
1799 | |
1800 | IOLockLock(gIOUserClientOwnersLock); |
1801 | |
1802 | taskque = task_io_user_clients(task); |
1803 | queue_iterate(taskque, iter, IOUserClientOwner *, taskLink) { |
1804 | userServers->setObject(iter->uc); |
1805 | } |
1806 | IOLockUnlock(gIOUserClientOwnersLock); |
1807 | |
1808 | if (userServers) { |
1809 | IOUserServer * userServer; |
1810 | while ((userServer = OSRequiredCast(IOUserServer, userServers->getAnyObject()))) { |
1811 | userServer->clientDied(); |
1812 | userServers->removeObject(anObject: userServer); |
1813 | } |
1814 | userServers->release(); |
1815 | } |
1816 | return KERN_SUCCESS; |
1817 | } |
1818 | |
1819 | static kern_return_t |
1820 | iokit_task_terminate_phase2(task_t task) |
1821 | { |
1822 | queue_head_t * taskque; |
1823 | IOUserClientOwner * owner; |
1824 | IOUserClient * dead; |
1825 | IOUserClient * uc; |
1826 | |
1827 | IOLockLock(gIOUserClientOwnersLock); |
1828 | taskque = task_io_user_clients(task); |
1829 | dead = NULL; |
1830 | while (!queue_empty(taskque)) { |
1831 | owner = (IOUserClientOwner *)(void *) queue_first(taskque); |
1832 | uc = owner->uc; |
1833 | queue_remove(taskque, owner, IOUserClientOwner *, taskLink); |
1834 | queue_remove(&uc->owners, owner, IOUserClientOwner *, ucLink); |
1835 | if (queue_empty(&uc->owners)) { |
1836 | uc->retain(); |
1837 | IOLog(format: "destroying out of band connect for %s\n" , uc->getName()); |
1838 | // now using the uc queue head as a singly linked queue, |
1839 | // leaving .next as NULL to mark it empty |
1840 | uc->owners.next = NULL; |
1841 | uc->owners.prev = (queue_entry_t) dead; |
1842 | dead = uc; |
1843 | } |
1844 | IOFreeType(owner, IOUserClientOwner); |
1845 | } |
1846 | IOLockUnlock(gIOUserClientOwnersLock); |
1847 | |
1848 | while (dead) { |
1849 | uc = dead; |
1850 | dead = (IOUserClient *)(void *) dead->owners.prev; |
1851 | uc->owners.prev = NULL; |
1852 | if (uc->sharedInstance || !uc->closed) { |
1853 | uc->clientDied(); |
1854 | } |
1855 | uc->release(); |
1856 | } |
1857 | |
1858 | return KERN_SUCCESS; |
1859 | } |
1860 | |
1861 | extern "C" kern_return_t |
1862 | iokit_task_terminate(task_t task, int phase) |
1863 | { |
1864 | switch (phase) { |
1865 | case 1: |
1866 | return iokit_task_terminate_phase1(task); |
1867 | case 2: |
1868 | return iokit_task_terminate_phase2(task); |
1869 | default: |
1870 | panic("iokit_task_terminate phase %d" , phase); |
1871 | } |
1872 | } |
1873 | |
1874 | struct IOUCFilterPolicy { |
1875 | task_t task; |
1876 | io_filter_policy_t filterPolicy; |
1877 | IOUCFilterPolicy * next; |
1878 | }; |
1879 | |
1880 | io_filter_policy_t |
1881 | IOUserClient::filterForTask(task_t task, io_filter_policy_t addFilterPolicy) |
1882 | { |
1883 | IOUCFilterPolicy * elem; |
1884 | io_filter_policy_t filterPolicy; |
1885 | |
1886 | filterPolicy = 0; |
1887 | IOLockLock(&filterLock); |
1888 | |
1889 | for (elem = reserved->filterPolicies; elem && (elem->task != task); elem = elem->next) { |
1890 | } |
1891 | |
1892 | if (elem) { |
1893 | if (addFilterPolicy) { |
1894 | assert(addFilterPolicy == elem->filterPolicy); |
1895 | } |
1896 | filterPolicy = elem->filterPolicy; |
1897 | } else if (addFilterPolicy) { |
1898 | elem = IOMallocType(IOUCFilterPolicy); |
1899 | elem->task = task; |
1900 | elem->filterPolicy = addFilterPolicy; |
1901 | elem->next = reserved->filterPolicies; |
1902 | reserved->filterPolicies = elem; |
1903 | filterPolicy = addFilterPolicy; |
1904 | } |
1905 | |
1906 | IOLockUnlock(&filterLock); |
1907 | return filterPolicy; |
1908 | } |
1909 | |
1910 | void |
1911 | IOUserClient::free() |
1912 | { |
1913 | if (mappings) { |
1914 | mappings->release(); |
1915 | } |
1916 | |
1917 | IOStatisticsUnregisterCounter(); |
1918 | |
1919 | assert(!owners.next); |
1920 | assert(!owners.prev); |
1921 | |
1922 | if (reserved) { |
1923 | IOUCFilterPolicy * elem; |
1924 | IOUCFilterPolicy * nextElem; |
1925 | for (elem = reserved->filterPolicies; elem; elem = nextElem) { |
1926 | nextElem = elem->next; |
1927 | if (elem->filterPolicy && gIOUCFilterCallbacks->io_filter_release) { |
1928 | gIOUCFilterCallbacks->io_filter_release(elem->filterPolicy); |
1929 | } |
1930 | IOFreeType(elem, IOUCFilterPolicy); |
1931 | } |
1932 | IOFreeType(reserved, ExpansionData); |
1933 | IORWLockInlineDestroy(&lock); |
1934 | IOLockInlineDestroy(&filterLock); |
1935 | } |
1936 | |
1937 | super::free(); |
1938 | } |
1939 | |
1940 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
1941 | |
1942 | OSDefineMetaClassAndAbstractStructors( IOUserClient2022, IOUserClient ) |
1943 | |
1944 | |
1945 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
1946 | |
1947 | IOReturn |
1948 | IOUserClient::clientDied( void ) |
1949 | { |
1950 | IOReturn ret = kIOReturnNotReady; |
1951 | |
1952 | if (sharedInstance || OSCompareAndSwap8(0, 1, &closed)) { |
1953 | ret = clientClose(); |
1954 | } |
1955 | |
1956 | return ret; |
1957 | } |
1958 | |
1959 | IOReturn |
1960 | IOUserClient::clientClose( void ) |
1961 | { |
1962 | return kIOReturnUnsupported; |
1963 | } |
1964 | |
1965 | IOService * |
1966 | IOUserClient::getService( void ) |
1967 | { |
1968 | return NULL; |
1969 | } |
1970 | |
1971 | IOReturn |
1972 | IOUserClient::registerNotificationPort( |
1973 | mach_port_t /* port */, |
1974 | UInt32 /* type */, |
1975 | UInt32 /* refCon */) |
1976 | { |
1977 | return kIOReturnUnsupported; |
1978 | } |
1979 | |
1980 | IOReturn |
1981 | IOUserClient::registerNotificationPort( |
1982 | mach_port_t port, |
1983 | UInt32 type, |
1984 | io_user_reference_t refCon) |
1985 | { |
1986 | return registerNotificationPort(port, type, (UInt32) refCon); |
1987 | } |
1988 | |
1989 | IOReturn |
1990 | IOUserClient::getNotificationSemaphore( UInt32 notification_type, |
1991 | semaphore_t * semaphore ) |
1992 | { |
1993 | return kIOReturnUnsupported; |
1994 | } |
1995 | |
1996 | IOReturn |
1997 | IOUserClient::connectClient( IOUserClient * /* client */ ) |
1998 | { |
1999 | return kIOReturnUnsupported; |
2000 | } |
2001 | |
2002 | IOReturn |
2003 | IOUserClient::clientMemoryForType( UInt32 type, |
2004 | IOOptionBits * options, |
2005 | IOMemoryDescriptor ** memory ) |
2006 | { |
2007 | return kIOReturnUnsupported; |
2008 | } |
2009 | |
2010 | IOReturn |
2011 | IOUserClient::clientMemoryForType( UInt32 type, |
2012 | IOOptionBits * options, |
2013 | OSSharedPtr<IOMemoryDescriptor>& memory ) |
2014 | { |
2015 | IOMemoryDescriptor* memoryRaw = nullptr; |
2016 | IOReturn result = clientMemoryForType(type, options, memory: &memoryRaw); |
2017 | memory.reset(p: memoryRaw, OSNoRetain); |
2018 | return result; |
2019 | } |
2020 | |
2021 | #if !__LP64__ |
2022 | IOMemoryMap * |
2023 | IOUserClient::mapClientMemory( |
2024 | IOOptionBits type, |
2025 | task_t task, |
2026 | IOOptionBits mapFlags, |
2027 | IOVirtualAddress atAddress ) |
2028 | { |
2029 | return NULL; |
2030 | } |
2031 | #endif |
2032 | |
2033 | IOMemoryMap * |
2034 | IOUserClient::mapClientMemory64( |
2035 | IOOptionBits type, |
2036 | task_t task, |
2037 | IOOptionBits mapFlags, |
2038 | mach_vm_address_t atAddress ) |
2039 | { |
2040 | IOReturn err; |
2041 | IOOptionBits options = 0; |
2042 | IOMemoryDescriptor * memory = NULL; |
2043 | IOMemoryMap * map = NULL; |
2044 | |
2045 | err = clientMemoryForType(type: (UInt32) type, options: &options, memory: &memory ); |
2046 | |
2047 | if (memory && (kIOReturnSuccess == err)) { |
2048 | FAKE_STACK_FRAME(getMetaClass()); |
2049 | |
2050 | options = (options & ~kIOMapUserOptionsMask) |
2051 | | (mapFlags & kIOMapUserOptionsMask); |
2052 | map = memory->createMappingInTask( intoTask: task, atAddress, options ); |
2053 | memory->release(); |
2054 | |
2055 | FAKE_STACK_FRAME_END(); |
2056 | } |
2057 | |
2058 | return map; |
2059 | } |
2060 | |
2061 | IOReturn |
2062 | IOUserClient::exportObjectToClient(task_t task, |
2063 | OSObject *obj, io_object_t *clientObj) |
2064 | { |
2065 | mach_port_name_t name; |
2066 | |
2067 | name = IOMachPort::makeSendRightForTask( task, obj, type: IKOT_IOKIT_OBJECT ); |
2068 | |
2069 | *clientObj = (io_object_t)(uintptr_t) name; |
2070 | |
2071 | if (obj) { |
2072 | obj->release(); |
2073 | } |
2074 | |
2075 | return kIOReturnSuccess; |
2076 | } |
2077 | |
2078 | IOReturn |
2079 | IOUserClient::copyPortNameForObjectInTask(task_t task, |
2080 | OSObject *obj, mach_port_name_t * port_name) |
2081 | { |
2082 | mach_port_name_t name; |
2083 | |
2084 | name = IOMachPort::makeSendRightForTask( task, obj, type: IKOT_IOKIT_IDENT ); |
2085 | |
2086 | *(mach_port_name_t *) port_name = name; |
2087 | |
2088 | return kIOReturnSuccess; |
2089 | } |
2090 | |
2091 | IOReturn |
2092 | IOUserClient::copyObjectForPortNameInTask(task_t task, mach_port_name_t port_name, |
2093 | OSObject **obj) |
2094 | { |
2095 | OSObject * object; |
2096 | |
2097 | object = iokit_lookup_object_with_port_name(name: port_name, type: IKOT_IOKIT_IDENT, task); |
2098 | |
2099 | *obj = object; |
2100 | |
2101 | return object ? kIOReturnSuccess : kIOReturnIPCError; |
2102 | } |
2103 | |
2104 | IOReturn |
2105 | IOUserClient::copyObjectForPortNameInTask(task_t task, mach_port_name_t port_name, |
2106 | OSSharedPtr<OSObject>& obj) |
2107 | { |
2108 | OSObject* objRaw = NULL; |
2109 | IOReturn result = copyObjectForPortNameInTask(task, port_name, obj: &objRaw); |
2110 | obj.reset(p: objRaw, OSNoRetain); |
2111 | return result; |
2112 | } |
2113 | |
2114 | IOReturn |
2115 | IOUserClient::adjustPortNameReferencesInTask(task_t task, mach_port_name_t port_name, mach_port_delta_t delta) |
2116 | { |
2117 | return iokit_mod_send_right(task, name: port_name, delta); |
2118 | } |
2119 | |
2120 | IOExternalMethod * |
2121 | IOUserClient::getExternalMethodForIndex( UInt32 /* index */) |
2122 | { |
2123 | return NULL; |
2124 | } |
2125 | |
2126 | IOExternalAsyncMethod * |
2127 | IOUserClient::getExternalAsyncMethodForIndex( UInt32 /* index */) |
2128 | { |
2129 | return NULL; |
2130 | } |
2131 | |
2132 | IOExternalTrap * |
2133 | IOUserClient:: |
2134 | getExternalTrapForIndex(UInt32 index) |
2135 | { |
2136 | return NULL; |
2137 | } |
2138 | |
2139 | #pragma clang diagnostic push |
2140 | #pragma clang diagnostic ignored "-Wdeprecated-declarations" |
2141 | |
2142 | // Suppressing the deprecated-declarations warning. Avoiding the use of deprecated |
2143 | // functions can break clients of kexts implementing getExternalMethodForIndex() |
2144 | IOExternalMethod * |
2145 | IOUserClient:: |
2146 | getTargetAndMethodForIndex(IOService **targetP, UInt32 index) |
2147 | { |
2148 | IOExternalMethod *method = getExternalMethodForIndex(index); |
2149 | |
2150 | if (method) { |
2151 | *targetP = (IOService *) method->object; |
2152 | } |
2153 | |
2154 | return method; |
2155 | } |
2156 | |
2157 | IOExternalMethod * |
2158 | IOUserClient:: |
2159 | getTargetAndMethodForIndex(OSSharedPtr<IOService>& targetP, UInt32 index) |
2160 | { |
2161 | IOService* targetPRaw = NULL; |
2162 | IOExternalMethod* result = getTargetAndMethodForIndex(targetP: &targetPRaw, index); |
2163 | targetP.reset(p: targetPRaw, OSRetain); |
2164 | return result; |
2165 | } |
2166 | |
2167 | IOExternalAsyncMethod * |
2168 | IOUserClient:: |
2169 | getAsyncTargetAndMethodForIndex(IOService ** targetP, UInt32 index) |
2170 | { |
2171 | IOExternalAsyncMethod *method = getExternalAsyncMethodForIndex(index); |
2172 | |
2173 | if (method) { |
2174 | *targetP = (IOService *) method->object; |
2175 | } |
2176 | |
2177 | return method; |
2178 | } |
2179 | |
2180 | IOExternalAsyncMethod * |
2181 | IOUserClient:: |
2182 | getAsyncTargetAndMethodForIndex(OSSharedPtr<IOService>& targetP, UInt32 index) |
2183 | { |
2184 | IOService* targetPRaw = NULL; |
2185 | IOExternalAsyncMethod* result = getAsyncTargetAndMethodForIndex(targetP: &targetPRaw, index); |
2186 | targetP.reset(p: targetPRaw, OSRetain); |
2187 | return result; |
2188 | } |
2189 | |
2190 | IOExternalTrap * |
2191 | IOUserClient:: |
2192 | getTargetAndTrapForIndex(IOService ** targetP, UInt32 index) |
2193 | { |
2194 | IOExternalTrap *trap = getExternalTrapForIndex(index); |
2195 | |
2196 | if (trap) { |
2197 | *targetP = trap->object; |
2198 | } |
2199 | |
2200 | return trap; |
2201 | } |
2202 | #pragma clang diagnostic pop |
2203 | |
2204 | IOReturn |
2205 | IOUserClient::releaseAsyncReference64(OSAsyncReference64 reference) |
2206 | { |
2207 | mach_port_t port; |
2208 | port = (mach_port_t) (reference[0] & ~kIOUCAsync0Flags); |
2209 | |
2210 | if (MACH_PORT_NULL != port) { |
2211 | iokit_release_port_send(port); |
2212 | } |
2213 | |
2214 | return kIOReturnSuccess; |
2215 | } |
2216 | |
2217 | IOReturn |
2218 | IOUserClient::releaseNotificationPort(mach_port_t port) |
2219 | { |
2220 | if (MACH_PORT_NULL != port) { |
2221 | iokit_release_port_send(port); |
2222 | } |
2223 | |
2224 | return kIOReturnSuccess; |
2225 | } |
2226 | |
2227 | IOReturn |
2228 | IOUserClient::sendAsyncResult(OSAsyncReference reference, |
2229 | IOReturn result, void *args[], UInt32 numArgs) |
2230 | { |
2231 | OSAsyncReference64 reference64; |
2232 | OSBoundedArray<io_user_reference_t, kMaxAsyncArgs> args64; |
2233 | unsigned int idx; |
2234 | |
2235 | if (numArgs > kMaxAsyncArgs) { |
2236 | return kIOReturnMessageTooLarge; |
2237 | } |
2238 | |
2239 | for (idx = 0; idx < kOSAsyncRef64Count; idx++) { |
2240 | reference64[idx] = REF64(reference[idx]); |
2241 | } |
2242 | |
2243 | for (idx = 0; idx < numArgs; idx++) { |
2244 | args64[idx] = REF64(args[idx]); |
2245 | } |
2246 | |
2247 | return sendAsyncResult64(reference: reference64, result, args: args64.data(), numArgs); |
2248 | } |
2249 | |
2250 | IOReturn |
2251 | IOUserClient::sendAsyncResult64WithOptions(OSAsyncReference64 reference, |
2252 | IOReturn result, io_user_reference_t args[], UInt32 numArgs, IOOptionBits options) |
2253 | { |
2254 | return _sendAsyncResult64(reference, result, args, numArgs, options); |
2255 | } |
2256 | |
2257 | IOReturn |
2258 | IOUserClient::sendAsyncResult64(OSAsyncReference64 reference, |
2259 | IOReturn result, io_user_reference_t args[], UInt32 numArgs) |
2260 | { |
2261 | return _sendAsyncResult64(reference, result, args, numArgs, options: 0); |
2262 | } |
2263 | |
2264 | IOReturn |
2265 | IOUserClient::_sendAsyncResult64(OSAsyncReference64 reference, |
2266 | IOReturn result, io_user_reference_t args[], UInt32 numArgs, IOOptionBits options) |
2267 | { |
2268 | struct ReplyMsg { |
2269 | mach_msg_header_t msgHdr; |
2270 | union{ |
2271 | struct{ |
2272 | OSNotificationHeader notifyHdr; |
2273 | IOAsyncCompletionContent asyncContent; |
2274 | uint32_t args[kMaxAsyncArgs]; |
2275 | } msg32; |
2276 | struct{ |
2277 | OSNotificationHeader64 notifyHdr; |
2278 | IOAsyncCompletionContent asyncContent; |
2279 | io_user_reference_t args[kMaxAsyncArgs] __attribute__ ((packed)); |
2280 | } msg64; |
2281 | } m; |
2282 | }; |
2283 | ReplyMsg replyMsg; |
2284 | mach_port_t replyPort; |
2285 | kern_return_t kr; |
2286 | |
2287 | // If no reply port, do nothing. |
2288 | replyPort = (mach_port_t) (reference[0] & ~kIOUCAsync0Flags); |
2289 | if (replyPort == MACH_PORT_NULL) { |
2290 | return kIOReturnSuccess; |
2291 | } |
2292 | |
2293 | if (numArgs > kMaxAsyncArgs) { |
2294 | return kIOReturnMessageTooLarge; |
2295 | } |
2296 | |
2297 | bzero(s: &replyMsg, n: sizeof(replyMsg)); |
2298 | replyMsg.msgHdr.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND /*remote*/, |
2299 | 0 /*local*/); |
2300 | replyMsg.msgHdr.msgh_remote_port = replyPort; |
2301 | replyMsg.msgHdr.msgh_local_port = NULL; |
2302 | replyMsg.msgHdr.msgh_id = kOSNotificationMessageID; |
2303 | if (kIOUCAsync64Flag & reference[0]) { |
2304 | replyMsg.msgHdr.msgh_size = |
2305 | sizeof(replyMsg.msgHdr) + sizeof(replyMsg.m.msg64) |
2306 | - (kMaxAsyncArgs - numArgs) * sizeof(io_user_reference_t); |
2307 | replyMsg.m.msg64.notifyHdr.size = sizeof(IOAsyncCompletionContent) |
2308 | + numArgs * sizeof(io_user_reference_t); |
2309 | replyMsg.m.msg64.notifyHdr.type = kIOAsyncCompletionNotificationType; |
2310 | /* Copy reference except for reference[0], which is left as 0 from the earlier bzero */ |
2311 | bcopy(src: &reference[1], dst: &replyMsg.m.msg64.notifyHdr.reference[1], n: sizeof(OSAsyncReference64) - sizeof(reference[0])); |
2312 | |
2313 | replyMsg.m.msg64.asyncContent.result = result; |
2314 | if (numArgs) { |
2315 | bcopy(src: args, dst: replyMsg.m.msg64.args, n: numArgs * sizeof(io_user_reference_t)); |
2316 | } |
2317 | } else { |
2318 | unsigned int idx; |
2319 | |
2320 | replyMsg.msgHdr.msgh_size = |
2321 | sizeof(replyMsg.msgHdr) + sizeof(replyMsg.m.msg32) |
2322 | - (kMaxAsyncArgs - numArgs) * sizeof(uint32_t); |
2323 | |
2324 | replyMsg.m.msg32.notifyHdr.size = sizeof(IOAsyncCompletionContent) |
2325 | + numArgs * sizeof(uint32_t); |
2326 | replyMsg.m.msg32.notifyHdr.type = kIOAsyncCompletionNotificationType; |
2327 | |
2328 | /* Skip reference[0] which is left as 0 from the earlier bzero */ |
2329 | for (idx = 1; idx < kOSAsyncRefCount; idx++) { |
2330 | replyMsg.m.msg32.notifyHdr.reference[idx] = REF32(reference[idx]); |
2331 | } |
2332 | |
2333 | replyMsg.m.msg32.asyncContent.result = result; |
2334 | |
2335 | for (idx = 0; idx < numArgs; idx++) { |
2336 | replyMsg.m.msg32.args[idx] = REF32(args[idx]); |
2337 | } |
2338 | } |
2339 | |
2340 | if ((options & kIOUserNotifyOptionCanDrop) != 0) { |
2341 | kr = mach_msg_send_from_kernel_with_options( msg: &replyMsg.msgHdr, |
2342 | send_size: replyMsg.msgHdr.msgh_size, MACH_SEND_TIMEOUT, MACH_MSG_TIMEOUT_NONE); |
2343 | } else { |
2344 | /* Fail on full queue. */ |
2345 | kr = mach_msg_send_from_kernel_proper( msg: &replyMsg.msgHdr, |
2346 | send_size: replyMsg.msgHdr.msgh_size); |
2347 | } |
2348 | if ((KERN_SUCCESS != kr) && (MACH_SEND_TIMED_OUT != kr) && !(kIOUCAsyncErrorLoggedFlag & reference[0])) { |
2349 | reference[0] |= kIOUCAsyncErrorLoggedFlag; |
2350 | IOLog(format: "%s: mach_msg_send_from_kernel_proper(0x%x)\n" , __PRETTY_FUNCTION__, kr ); |
2351 | } |
2352 | return kr; |
2353 | } |
2354 | |
2355 | |
2356 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
2357 | |
2358 | extern "C" { |
2359 | #define CHECK(cls, obj, out) \ |
2360 | cls * out; \ |
2361 | if( !(out = OSDynamicCast( cls, obj))) \ |
2362 | return( kIOReturnBadArgument ) |
2363 | |
2364 | #define CHECKLOCKED(cls, obj, out) \ |
2365 | IOUserIterator * oIter; \ |
2366 | cls * out; \ |
2367 | if( !(oIter = OSDynamicCast(IOUserIterator, obj))) \ |
2368 | return (kIOReturnBadArgument); \ |
2369 | if( !(out = OSDynamicCast(cls, oIter->userIteratorObject))) \ |
2370 | return (kIOReturnBadArgument) |
2371 | |
2372 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
2373 | |
2374 | // Create a vm_map_copy_t or kalloc'ed data for memory |
2375 | // to be copied out. ipc will free after the copyout. |
2376 | |
2377 | static kern_return_t |
2378 | copyoutkdata( const void * data, vm_size_t len, |
2379 | io_buf_ptr_t * buf ) |
2380 | { |
2381 | kern_return_t err; |
2382 | vm_map_copy_t copy; |
2383 | |
2384 | err = vm_map_copyin( src_map: kernel_map, CAST_USER_ADDR_T(data), len, |
2385 | src_destroy: false /* src_destroy */, copy_result: ©); |
2386 | |
2387 | assert( err == KERN_SUCCESS ); |
2388 | if (err == KERN_SUCCESS) { |
2389 | *buf = (char *) copy; |
2390 | } |
2391 | |
2392 | return err; |
2393 | } |
2394 | |
2395 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
2396 | |
2397 | /* Routine io_server_version */ |
2398 | kern_return_t |
2399 | is_io_server_version( |
2400 | mach_port_t main_port, |
2401 | uint64_t *version) |
2402 | { |
2403 | *version = IOKIT_SERVER_VERSION; |
2404 | return kIOReturnSuccess; |
2405 | } |
2406 | |
2407 | /* Routine io_object_get_class */ |
2408 | kern_return_t |
2409 | is_io_object_get_class( |
2410 | io_object_t object, |
2411 | io_name_t className ) |
2412 | { |
2413 | const OSMetaClass* my_obj = NULL; |
2414 | |
2415 | if (!object) { |
2416 | return kIOReturnBadArgument; |
2417 | } |
2418 | |
2419 | my_obj = object->getMetaClass(); |
2420 | if (!my_obj) { |
2421 | return kIOReturnNotFound; |
2422 | } |
2423 | |
2424 | strlcpy( dst: className, src: my_obj->getClassName(), n: sizeof(io_name_t)); |
2425 | |
2426 | return kIOReturnSuccess; |
2427 | } |
2428 | |
2429 | /* Routine io_object_get_superclass */ |
2430 | kern_return_t |
2431 | is_io_object_get_superclass( |
2432 | mach_port_t main_port, |
2433 | io_name_t obj_name, |
2434 | io_name_t class_name) |
2435 | { |
2436 | IOReturn ret; |
2437 | const OSMetaClass * meta; |
2438 | const OSMetaClass * super; |
2439 | const OSSymbol * name; |
2440 | const char * cstr; |
2441 | |
2442 | if (!obj_name || !class_name) { |
2443 | return kIOReturnBadArgument; |
2444 | } |
2445 | if (main_port != main_device_port) { |
2446 | return kIOReturnNotPrivileged; |
2447 | } |
2448 | |
2449 | ret = kIOReturnNotFound; |
2450 | meta = NULL; |
2451 | do{ |
2452 | name = OSSymbol::withCString(cString: obj_name); |
2453 | if (!name) { |
2454 | break; |
2455 | } |
2456 | meta = OSMetaClass::copyMetaClassWithName(name); |
2457 | if (!meta) { |
2458 | break; |
2459 | } |
2460 | super = meta->getSuperClass(); |
2461 | if (!super) { |
2462 | break; |
2463 | } |
2464 | cstr = super->getClassName(); |
2465 | if (!cstr) { |
2466 | break; |
2467 | } |
2468 | strlcpy(dst: class_name, src: cstr, n: sizeof(io_name_t)); |
2469 | ret = kIOReturnSuccess; |
2470 | }while (false); |
2471 | |
2472 | OSSafeReleaseNULL(name); |
2473 | if (meta) { |
2474 | meta->releaseMetaClass(); |
2475 | } |
2476 | |
2477 | return ret; |
2478 | } |
2479 | |
2480 | /* Routine io_object_get_bundle_identifier */ |
2481 | kern_return_t |
2482 | is_io_object_get_bundle_identifier( |
2483 | mach_port_t main_port, |
2484 | io_name_t obj_name, |
2485 | io_name_t bundle_name) |
2486 | { |
2487 | IOReturn ret; |
2488 | const OSMetaClass * meta; |
2489 | const OSSymbol * name; |
2490 | const OSSymbol * identifier; |
2491 | const char * cstr; |
2492 | |
2493 | if (!obj_name || !bundle_name) { |
2494 | return kIOReturnBadArgument; |
2495 | } |
2496 | if (main_port != main_device_port) { |
2497 | return kIOReturnNotPrivileged; |
2498 | } |
2499 | |
2500 | ret = kIOReturnNotFound; |
2501 | meta = NULL; |
2502 | do{ |
2503 | name = OSSymbol::withCString(cString: obj_name); |
2504 | if (!name) { |
2505 | break; |
2506 | } |
2507 | meta = OSMetaClass::copyMetaClassWithName(name); |
2508 | if (!meta) { |
2509 | break; |
2510 | } |
2511 | identifier = meta->getKmodName(); |
2512 | if (!identifier) { |
2513 | break; |
2514 | } |
2515 | cstr = identifier->getCStringNoCopy(); |
2516 | if (!cstr) { |
2517 | break; |
2518 | } |
2519 | strlcpy(dst: bundle_name, src: identifier->getCStringNoCopy(), n: sizeof(io_name_t)); |
2520 | ret = kIOReturnSuccess; |
2521 | }while (false); |
2522 | |
2523 | OSSafeReleaseNULL(name); |
2524 | if (meta) { |
2525 | meta->releaseMetaClass(); |
2526 | } |
2527 | |
2528 | return ret; |
2529 | } |
2530 | |
2531 | /* Routine io_object_conforms_to */ |
2532 | kern_return_t |
2533 | is_io_object_conforms_to( |
2534 | io_object_t object, |
2535 | io_name_t className, |
2536 | boolean_t *conforms ) |
2537 | { |
2538 | if (!object) { |
2539 | return kIOReturnBadArgument; |
2540 | } |
2541 | |
2542 | *conforms = (NULL != object->metaCast( toMeta: className )); |
2543 | |
2544 | return kIOReturnSuccess; |
2545 | } |
2546 | |
2547 | /* Routine io_object_get_retain_count */ |
2548 | kern_return_t |
2549 | is_io_object_get_retain_count( |
2550 | io_object_t object, |
2551 | uint32_t *retainCount ) |
2552 | { |
2553 | if (!object) { |
2554 | return kIOReturnBadArgument; |
2555 | } |
2556 | |
2557 | *retainCount = object->getRetainCount(); |
2558 | return kIOReturnSuccess; |
2559 | } |
2560 | |
2561 | /* Routine io_iterator_next */ |
2562 | kern_return_t |
2563 | is_io_iterator_next( |
2564 | io_object_t iterator, |
2565 | io_object_t *object ) |
2566 | { |
2567 | IOReturn ret; |
2568 | OSObject * obj; |
2569 | OSIterator * iter; |
2570 | IOUserIterator * uiter; |
2571 | |
2572 | if ((uiter = OSDynamicCast(IOUserIterator, iterator))) { |
2573 | obj = uiter->copyNextObject(); |
2574 | } else if ((iter = OSDynamicCast(OSIterator, iterator))) { |
2575 | obj = iter->getNextObject(); |
2576 | if (obj) { |
2577 | obj->retain(); |
2578 | } |
2579 | } else { |
2580 | return kIOReturnBadArgument; |
2581 | } |
2582 | |
2583 | if (obj) { |
2584 | *object = obj; |
2585 | ret = kIOReturnSuccess; |
2586 | } else { |
2587 | ret = kIOReturnNoDevice; |
2588 | } |
2589 | |
2590 | return ret; |
2591 | } |
2592 | |
2593 | /* Routine io_iterator_reset */ |
2594 | kern_return_t |
2595 | is_io_iterator_reset( |
2596 | io_object_t iterator ) |
2597 | { |
2598 | CHECK( OSIterator, iterator, iter ); |
2599 | |
2600 | iter->reset(); |
2601 | |
2602 | return kIOReturnSuccess; |
2603 | } |
2604 | |
2605 | /* Routine io_iterator_is_valid */ |
2606 | kern_return_t |
2607 | is_io_iterator_is_valid( |
2608 | io_object_t iterator, |
2609 | boolean_t *is_valid ) |
2610 | { |
2611 | CHECK( OSIterator, iterator, iter ); |
2612 | |
2613 | *is_valid = iter->isValid(); |
2614 | |
2615 | return kIOReturnSuccess; |
2616 | } |
2617 | |
2618 | static kern_return_t |
2619 | internal_io_service_match_property_table( |
2620 | io_service_t _service, |
2621 | const char * matching, |
2622 | mach_msg_type_number_t matching_size, |
2623 | boolean_t *matches) |
2624 | { |
2625 | CHECK( IOService, _service, service ); |
2626 | |
2627 | kern_return_t kr; |
2628 | OSObject * obj; |
2629 | OSDictionary * dict; |
2630 | |
2631 | assert(matching_size); |
2632 | |
2633 | |
2634 | obj = OSUnserializeXML(buffer: matching, bufferSize: matching_size); |
2635 | |
2636 | if ((dict = OSDynamicCast( OSDictionary, obj))) { |
2637 | IOTaskRegistryCompatibilityMatching(task: current_task(), matching: dict); |
2638 | *matches = service->passiveMatch( matching: dict ); |
2639 | kr = kIOReturnSuccess; |
2640 | } else { |
2641 | kr = kIOReturnBadArgument; |
2642 | } |
2643 | |
2644 | if (obj) { |
2645 | obj->release(); |
2646 | } |
2647 | |
2648 | return kr; |
2649 | } |
2650 | |
2651 | /* Routine io_service_match_property_table */ |
2652 | kern_return_t |
2653 | is_io_service_match_property_table( |
2654 | io_service_t service, |
2655 | io_string_t matching, |
2656 | boolean_t *matches ) |
2657 | { |
2658 | return kIOReturnUnsupported; |
2659 | } |
2660 | |
2661 | |
2662 | /* Routine io_service_match_property_table_ool */ |
2663 | kern_return_t |
2664 | is_io_service_match_property_table_ool( |
2665 | io_object_t service, |
2666 | io_buf_ptr_t matching, |
2667 | mach_msg_type_number_t matchingCnt, |
2668 | kern_return_t *result, |
2669 | boolean_t *matches ) |
2670 | { |
2671 | kern_return_t kr; |
2672 | vm_offset_t data; |
2673 | vm_map_offset_t map_data; |
2674 | |
2675 | kr = vm_map_copyout( dst_map: kernel_map, dst_addr: &map_data, copy: (vm_map_copy_t) matching ); |
2676 | data = CAST_DOWN(vm_offset_t, map_data); |
2677 | |
2678 | if (KERN_SUCCESS == kr) { |
2679 | // must return success after vm_map_copyout() succeeds |
2680 | *result = internal_io_service_match_property_table(service: service, |
2681 | matching: (const char *)data, matching_size: matchingCnt, matches ); |
2682 | vm_deallocate( target_task: kernel_map, address: data, size: matchingCnt ); |
2683 | } |
2684 | |
2685 | return kr; |
2686 | } |
2687 | |
2688 | /* Routine io_service_match_property_table_bin */ |
2689 | kern_return_t |
2690 | is_io_service_match_property_table_bin( |
2691 | io_object_t service, |
2692 | io_struct_inband_t matching, |
2693 | mach_msg_type_number_t matchingCnt, |
2694 | boolean_t *matches) |
2695 | { |
2696 | return internal_io_service_match_property_table(service: service, matching, matching_size: matchingCnt, matches); |
2697 | } |
2698 | |
2699 | static kern_return_t |
2700 | internal_io_service_get_matching_services( |
2701 | mach_port_t main_port, |
2702 | const char * matching, |
2703 | mach_msg_type_number_t matching_size, |
2704 | io_iterator_t *existing ) |
2705 | { |
2706 | kern_return_t kr; |
2707 | OSObject * obj; |
2708 | OSDictionary * dict; |
2709 | |
2710 | if (main_port != main_device_port) { |
2711 | return kIOReturnNotPrivileged; |
2712 | } |
2713 | |
2714 | assert(matching_size); |
2715 | obj = OSUnserializeXML(buffer: matching, bufferSize: matching_size); |
2716 | |
2717 | if ((dict = OSDynamicCast( OSDictionary, obj))) { |
2718 | IOTaskRegistryCompatibilityMatching(task: current_task(), matching: dict); |
2719 | *existing = IOUserIterator::withIterator(iter: IOService::getMatchingServices( matching: dict )); |
2720 | kr = kIOReturnSuccess; |
2721 | } else { |
2722 | kr = kIOReturnBadArgument; |
2723 | } |
2724 | |
2725 | if (obj) { |
2726 | obj->release(); |
2727 | } |
2728 | |
2729 | return kr; |
2730 | } |
2731 | |
2732 | /* Routine io_service_get_matching_services */ |
2733 | kern_return_t |
2734 | is_io_service_get_matching_services( |
2735 | mach_port_t main_port, |
2736 | io_string_t matching, |
2737 | io_iterator_t *existing ) |
2738 | { |
2739 | return kIOReturnUnsupported; |
2740 | } |
2741 | |
2742 | /* Routine io_service_get_matching_services_ool */ |
2743 | kern_return_t |
2744 | is_io_service_get_matching_services_ool( |
2745 | mach_port_t main_port, |
2746 | io_buf_ptr_t matching, |
2747 | mach_msg_type_number_t matchingCnt, |
2748 | kern_return_t *result, |
2749 | io_object_t *existing ) |
2750 | { |
2751 | kern_return_t kr; |
2752 | vm_offset_t data; |
2753 | vm_map_offset_t map_data; |
2754 | |
2755 | kr = vm_map_copyout( dst_map: kernel_map, dst_addr: &map_data, copy: (vm_map_copy_t) matching ); |
2756 | data = CAST_DOWN(vm_offset_t, map_data); |
2757 | |
2758 | if (KERN_SUCCESS == kr) { |
2759 | // must return success after vm_map_copyout() succeeds |
2760 | // and mig will copy out objects on success |
2761 | *existing = NULL; |
2762 | *result = internal_io_service_get_matching_services(main_port, |
2763 | matching: (const char *) data, matching_size: matchingCnt, existing); |
2764 | vm_deallocate( target_task: kernel_map, address: data, size: matchingCnt ); |
2765 | } |
2766 | |
2767 | return kr; |
2768 | } |
2769 | |
2770 | /* Routine io_service_get_matching_services_bin */ |
2771 | kern_return_t |
2772 | is_io_service_get_matching_services_bin( |
2773 | mach_port_t main_port, |
2774 | io_struct_inband_t matching, |
2775 | mach_msg_type_number_t matchingCnt, |
2776 | io_object_t *existing) |
2777 | { |
2778 | return internal_io_service_get_matching_services(main_port, matching, matching_size: matchingCnt, existing); |
2779 | } |
2780 | |
2781 | |
2782 | static kern_return_t |
2783 | internal_io_service_get_matching_service( |
2784 | mach_port_t main_port, |
2785 | const char * matching, |
2786 | mach_msg_type_number_t matching_size, |
2787 | io_service_t *service ) |
2788 | { |
2789 | kern_return_t kr; |
2790 | OSObject * obj; |
2791 | OSDictionary * dict; |
2792 | |
2793 | if (main_port != main_device_port) { |
2794 | return kIOReturnNotPrivileged; |
2795 | } |
2796 | |
2797 | assert(matching_size); |
2798 | obj = OSUnserializeXML(buffer: matching, bufferSize: matching_size); |
2799 | |
2800 | if ((dict = OSDynamicCast( OSDictionary, obj))) { |
2801 | IOTaskRegistryCompatibilityMatching(task: current_task(), matching: dict); |
2802 | *service = IOService::copyMatchingService( matching: dict ); |
2803 | kr = *service ? kIOReturnSuccess : kIOReturnNotFound; |
2804 | } else { |
2805 | kr = kIOReturnBadArgument; |
2806 | } |
2807 | |
2808 | if (obj) { |
2809 | obj->release(); |
2810 | } |
2811 | |
2812 | return kr; |
2813 | } |
2814 | |
2815 | /* Routine io_service_get_matching_service */ |
2816 | kern_return_t |
2817 | is_io_service_get_matching_service( |
2818 | mach_port_t main_port, |
2819 | io_string_t matching, |
2820 | io_service_t *service ) |
2821 | { |
2822 | return kIOReturnUnsupported; |
2823 | } |
2824 | |
2825 | /* Routine io_service_get_matching_services_ool */ |
2826 | kern_return_t |
2827 | is_io_service_get_matching_service_ool( |
2828 | mach_port_t main_port, |
2829 | io_buf_ptr_t matching, |
2830 | mach_msg_type_number_t matchingCnt, |
2831 | kern_return_t *result, |
2832 | io_object_t *service ) |
2833 | { |
2834 | kern_return_t kr; |
2835 | vm_offset_t data; |
2836 | vm_map_offset_t map_data; |
2837 | |
2838 | kr = vm_map_copyout( dst_map: kernel_map, dst_addr: &map_data, copy: (vm_map_copy_t) matching ); |
2839 | data = CAST_DOWN(vm_offset_t, map_data); |
2840 | |
2841 | if (KERN_SUCCESS == kr) { |
2842 | // must return success after vm_map_copyout() succeeds |
2843 | // and mig will copy out objects on success |
2844 | *service = NULL; |
2845 | *result = internal_io_service_get_matching_service(main_port, |
2846 | matching: (const char *) data, matching_size: matchingCnt, service ); |
2847 | vm_deallocate( target_task: kernel_map, address: data, size: matchingCnt ); |
2848 | } |
2849 | |
2850 | return kr; |
2851 | } |
2852 | |
2853 | /* Routine io_service_get_matching_service_bin */ |
2854 | kern_return_t |
2855 | is_io_service_get_matching_service_bin( |
2856 | mach_port_t main_port, |
2857 | io_struct_inband_t matching, |
2858 | mach_msg_type_number_t matchingCnt, |
2859 | io_object_t *service) |
2860 | { |
2861 | return internal_io_service_get_matching_service(main_port, matching, matching_size: matchingCnt, service); |
2862 | } |
2863 | |
2864 | static kern_return_t |
2865 | internal_io_service_add_notification( |
2866 | mach_port_t main_port, |
2867 | io_name_t notification_type, |
2868 | const char * matching, |
2869 | size_t matching_size, |
2870 | mach_port_t port, |
2871 | void * reference, |
2872 | vm_size_t referenceSize, |
2873 | bool client64, |
2874 | io_object_t * notification ) |
2875 | { |
2876 | IOServiceUserNotification * userNotify = NULL; |
2877 | IONotifier * notify = NULL; |
2878 | const OSSymbol * sym; |
2879 | OSObject * obj; |
2880 | OSDictionary * dict; |
2881 | IOReturn err; |
2882 | natural_t userMsgType; |
2883 | |
2884 | if (main_port != main_device_port) { |
2885 | return kIOReturnNotPrivileged; |
2886 | } |
2887 | |
2888 | do { |
2889 | err = kIOReturnNoResources; |
2890 | |
2891 | if (matching_size > (sizeof(io_struct_inband_t) * 1024)) { |
2892 | return kIOReturnMessageTooLarge; |
2893 | } |
2894 | |
2895 | if (!(sym = OSSymbol::withCString( cString: notification_type ))) { |
2896 | err = kIOReturnNoResources; |
2897 | } |
2898 | |
2899 | assert(matching_size); |
2900 | obj = OSUnserializeXML(buffer: matching, bufferSize: matching_size); |
2901 | dict = OSDynamicCast(OSDictionary, obj); |
2902 | if (!dict) { |
2903 | err = kIOReturnBadArgument; |
2904 | continue; |
2905 | } |
2906 | IOTaskRegistryCompatibilityMatching(task: current_task(), matching: dict); |
2907 | |
2908 | if ((sym == gIOPublishNotification) |
2909 | || (sym == gIOFirstPublishNotification)) { |
2910 | userMsgType = kIOServicePublishNotificationType; |
2911 | } else if ((sym == gIOMatchedNotification) |
2912 | || (sym == gIOFirstMatchNotification)) { |
2913 | userMsgType = kIOServiceMatchedNotificationType; |
2914 | } else if ((sym == gIOTerminatedNotification) |
2915 | || (sym == gIOWillTerminateNotification)) { |
2916 | userMsgType = kIOServiceTerminatedNotificationType; |
2917 | } else { |
2918 | userMsgType = kLastIOKitNotificationType; |
2919 | } |
2920 | |
2921 | userNotify = new IOServiceUserNotification; |
2922 | |
2923 | if (userNotify && !userNotify->init( port, type: userMsgType, |
2924 | reference, referenceSize, clientIs64: client64)) { |
2925 | userNotify->release(); |
2926 | userNotify = NULL; |
2927 | } |
2928 | if (!userNotify) { |
2929 | continue; |
2930 | } |
2931 | |
2932 | notify = IOService::addMatchingNotification( type: sym, matching: dict, |
2933 | handler: &userNotify->_handler, target: userNotify ); |
2934 | if (notify) { |
2935 | *notification = userNotify; |
2936 | userNotify->setNotification( notify ); |
2937 | err = kIOReturnSuccess; |
2938 | } else { |
2939 | err = kIOReturnUnsupported; |
2940 | } |
2941 | } while (false); |
2942 | |
2943 | if ((kIOReturnSuccess != err) && userNotify) { |
2944 | userNotify->setNotification(NULL); |
2945 | userNotify->invalidatePort(); |
2946 | userNotify->release(); |
2947 | userNotify = NULL; |
2948 | } |
2949 | |
2950 | if (sym) { |
2951 | sym->release(); |
2952 | } |
2953 | if (obj) { |
2954 | obj->release(); |
2955 | } |
2956 | |
2957 | return err; |
2958 | } |
2959 | |
2960 | |
2961 | /* Routine io_service_add_notification */ |
2962 | kern_return_t |
2963 | is_io_service_add_notification( |
2964 | mach_port_t main_port, |
2965 | io_name_t notification_type, |
2966 | io_string_t matching, |
2967 | mach_port_t port, |
2968 | io_async_ref_t reference, |
2969 | mach_msg_type_number_t referenceCnt, |
2970 | io_object_t * notification ) |
2971 | { |
2972 | return kIOReturnUnsupported; |
2973 | } |
2974 | |
2975 | /* Routine io_service_add_notification_64 */ |
2976 | kern_return_t |
2977 | is_io_service_add_notification_64( |
2978 | mach_port_t main_port, |
2979 | io_name_t notification_type, |
2980 | io_string_t matching, |
2981 | mach_port_t wake_port, |
2982 | io_async_ref64_t reference, |
2983 | mach_msg_type_number_t referenceCnt, |
2984 | io_object_t *notification ) |
2985 | { |
2986 | return kIOReturnUnsupported; |
2987 | } |
2988 | |
2989 | /* Routine io_service_add_notification_bin */ |
2990 | kern_return_t |
2991 | is_io_service_add_notification_bin |
2992 | ( |
2993 | mach_port_t main_port, |
2994 | io_name_t notification_type, |
2995 | io_struct_inband_t matching, |
2996 | mach_msg_type_number_t matchingCnt, |
2997 | mach_port_t wake_port, |
2998 | io_async_ref_t reference, |
2999 | mach_msg_type_number_t referenceCnt, |
3000 | io_object_t *notification) |
3001 | { |
3002 | io_async_ref_t zreference; |
3003 | |
3004 | if (referenceCnt > ASYNC_REF_COUNT) { |
3005 | return kIOReturnBadArgument; |
3006 | } |
3007 | bcopy(src: &reference[0], dst: &zreference[0], n: referenceCnt * sizeof(zreference[0])); |
3008 | bzero(s: &zreference[referenceCnt], n: (ASYNC_REF_COUNT - referenceCnt) * sizeof(zreference[0])); |
3009 | |
3010 | return internal_io_service_add_notification(main_port, notification_type, |
3011 | matching, matching_size: matchingCnt, port: wake_port, reference: &zreference[0], referenceSize: sizeof(io_async_ref_t), |
3012 | client64: false, notification); |
3013 | } |
3014 | |
3015 | /* Routine io_service_add_notification_bin_64 */ |
3016 | kern_return_t |
3017 | is_io_service_add_notification_bin_64 |
3018 | ( |
3019 | mach_port_t main_port, |
3020 | io_name_t notification_type, |
3021 | io_struct_inband_t matching, |
3022 | mach_msg_type_number_t matchingCnt, |
3023 | mach_port_t wake_port, |
3024 | io_async_ref64_t reference, |
3025 | mach_msg_type_number_t referenceCnt, |
3026 | io_object_t *notification) |
3027 | { |
3028 | io_async_ref64_t zreference; |
3029 | |
3030 | if (referenceCnt > ASYNC_REF64_COUNT) { |
3031 | return kIOReturnBadArgument; |
3032 | } |
3033 | bcopy(src: &reference[0], dst: &zreference[0], n: referenceCnt * sizeof(zreference[0])); |
3034 | bzero(s: &zreference[referenceCnt], n: (ASYNC_REF64_COUNT - referenceCnt) * sizeof(zreference[0])); |
3035 | |
3036 | return internal_io_service_add_notification(main_port, notification_type, |
3037 | matching, matching_size: matchingCnt, port: wake_port, reference: &zreference[0], referenceSize: sizeof(io_async_ref64_t), |
3038 | client64: true, notification); |
3039 | } |
3040 | |
3041 | static kern_return_t |
3042 | internal_io_service_add_notification_ool( |
3043 | mach_port_t main_port, |
3044 | io_name_t notification_type, |
3045 | io_buf_ptr_t matching, |
3046 | mach_msg_type_number_t matchingCnt, |
3047 | mach_port_t wake_port, |
3048 | void * reference, |
3049 | vm_size_t referenceSize, |
3050 | bool client64, |
3051 | kern_return_t *result, |
3052 | io_object_t *notification ) |
3053 | { |
3054 | kern_return_t kr; |
3055 | vm_offset_t data; |
3056 | vm_map_offset_t map_data; |
3057 | |
3058 | kr = vm_map_copyout( dst_map: kernel_map, dst_addr: &map_data, copy: (vm_map_copy_t) matching ); |
3059 | data = CAST_DOWN(vm_offset_t, map_data); |
3060 | |
3061 | if (KERN_SUCCESS == kr) { |
3062 | // must return success after vm_map_copyout() succeeds |
3063 | // and mig will copy out objects on success |
3064 | *notification = NULL; |
3065 | *result = internal_io_service_add_notification( main_port, notification_type, |
3066 | matching: (char *) data, matching_size: matchingCnt, port: wake_port, reference, referenceSize, client64, notification ); |
3067 | vm_deallocate( target_task: kernel_map, address: data, size: matchingCnt ); |
3068 | } |
3069 | |
3070 | return kr; |
3071 | } |
3072 | |
3073 | /* Routine io_service_add_notification_ool */ |
3074 | kern_return_t |
3075 | is_io_service_add_notification_ool( |
3076 | mach_port_t main_port, |
3077 | io_name_t notification_type, |
3078 | io_buf_ptr_t matching, |
3079 | mach_msg_type_number_t matchingCnt, |
3080 | mach_port_t wake_port, |
3081 | io_async_ref_t reference, |
3082 | mach_msg_type_number_t referenceCnt, |
3083 | kern_return_t *result, |
3084 | io_object_t *notification ) |
3085 | { |
3086 | io_async_ref_t zreference; |
3087 | |
3088 | if (referenceCnt > ASYNC_REF_COUNT) { |
3089 | return kIOReturnBadArgument; |
3090 | } |
3091 | bcopy(src: &reference[0], dst: &zreference[0], n: referenceCnt * sizeof(zreference[0])); |
3092 | bzero(s: &zreference[referenceCnt], n: (ASYNC_REF_COUNT - referenceCnt) * sizeof(zreference[0])); |
3093 | |
3094 | return internal_io_service_add_notification_ool(main_port, notification_type, |
3095 | matching, matchingCnt, wake_port, reference: &zreference[0], referenceSize: sizeof(io_async_ref_t), |
3096 | client64: false, result, notification); |
3097 | } |
3098 | |
3099 | /* Routine io_service_add_notification_ool_64 */ |
3100 | kern_return_t |
3101 | is_io_service_add_notification_ool_64( |
3102 | mach_port_t main_port, |
3103 | io_name_t notification_type, |
3104 | io_buf_ptr_t matching, |
3105 | mach_msg_type_number_t matchingCnt, |
3106 | mach_port_t wake_port, |
3107 | io_async_ref64_t reference, |
3108 | mach_msg_type_number_t referenceCnt, |
3109 | kern_return_t *result, |
3110 | io_object_t *notification ) |
3111 | { |
3112 | io_async_ref64_t zreference; |
3113 | |
3114 | if (referenceCnt > ASYNC_REF64_COUNT) { |
3115 | return kIOReturnBadArgument; |
3116 | } |
3117 | bcopy(src: &reference[0], dst: &zreference[0], n: referenceCnt * sizeof(zreference[0])); |
3118 | bzero(s: &zreference[referenceCnt], n: (ASYNC_REF64_COUNT - referenceCnt) * sizeof(zreference[0])); |
3119 | |
3120 | return internal_io_service_add_notification_ool(main_port, notification_type, |
3121 | matching, matchingCnt, wake_port, reference: &zreference[0], referenceSize: sizeof(io_async_ref64_t), |
3122 | client64: true, result, notification); |
3123 | } |
3124 | |
3125 | /* Routine io_service_add_notification_old */ |
3126 | kern_return_t |
3127 | is_io_service_add_notification_old( |
3128 | mach_port_t main_port, |
3129 | io_name_t notification_type, |
3130 | io_string_t matching, |
3131 | mach_port_t port, |
3132 | // for binary compatibility reasons, this must be natural_t for ILP32 |
3133 | natural_t ref, |
3134 | io_object_t * notification ) |
3135 | { |
3136 | return is_io_service_add_notification( main_port, notification_type, |
3137 | matching, port, reference: &ref, referenceCnt: 1, notification ); |
3138 | } |
3139 | |
3140 | |
3141 | static kern_return_t |
3142 | internal_io_service_add_interest_notification( |
3143 | io_object_t _service, |
3144 | io_name_t type_of_interest, |
3145 | mach_port_t port, |
3146 | void * reference, |
3147 | vm_size_t referenceSize, |
3148 | bool client64, |
3149 | io_object_t * notification ) |
3150 | { |
3151 | IOServiceMessageUserNotification * userNotify = NULL; |
3152 | IONotifier * notify = NULL; |
3153 | const OSSymbol * sym; |
3154 | IOReturn err; |
3155 | |
3156 | CHECK( IOService, _service, service ); |
3157 | |
3158 | err = kIOReturnNoResources; |
3159 | if ((sym = OSSymbol::withCString( cString: type_of_interest ))) { |
3160 | do { |
3161 | userNotify = new IOServiceMessageUserNotification; |
3162 | |
3163 | if (userNotify && !userNotify->init( port, type: kIOServiceMessageNotificationType, |
3164 | reference, referenceSize, client64 )) { |
3165 | userNotify->release(); |
3166 | userNotify = NULL; |
3167 | } |
3168 | if (!userNotify) { |
3169 | continue; |
3170 | } |
3171 | |
3172 | notify = service->registerInterest( typeOfInterest: sym, |
3173 | handler: &userNotify->_handler, target: userNotify ); |
3174 | if (notify) { |
3175 | *notification = userNotify; |
3176 | userNotify->setNotification( notify ); |
3177 | err = kIOReturnSuccess; |
3178 | } else { |
3179 | err = kIOReturnUnsupported; |
3180 | } |
3181 | } while (false); |
3182 | |
3183 | sym->release(); |
3184 | } |
3185 | |
3186 | if ((kIOReturnSuccess != err) && userNotify) { |
3187 | userNotify->setNotification(NULL); |
3188 | userNotify->invalidatePort(); |
3189 | userNotify->release(); |
3190 | userNotify = NULL; |
3191 | } |
3192 | |
3193 | return err; |
3194 | } |
3195 | |
3196 | /* Routine io_service_add_message_notification */ |
3197 | kern_return_t |
3198 | is_io_service_add_interest_notification( |
3199 | io_object_t service, |
3200 | io_name_t type_of_interest, |
3201 | mach_port_t port, |
3202 | io_async_ref_t reference, |
3203 | mach_msg_type_number_t referenceCnt, |
3204 | io_object_t * notification ) |
3205 | { |
3206 | io_async_ref_t zreference; |
3207 | |
3208 | if (referenceCnt > ASYNC_REF_COUNT) { |
3209 | return kIOReturnBadArgument; |
3210 | } |
3211 | bcopy(src: &reference[0], dst: &zreference[0], n: referenceCnt * sizeof(zreference[0])); |
3212 | bzero(s: &zreference[referenceCnt], n: (ASYNC_REF_COUNT - referenceCnt) * sizeof(zreference[0])); |
3213 | |
3214 | return internal_io_service_add_interest_notification(service: service, type_of_interest, |
3215 | port, reference: &zreference[0], referenceSize: sizeof(io_async_ref_t), client64: false, notification); |
3216 | } |
3217 | |
3218 | /* Routine io_service_add_interest_notification_64 */ |
3219 | kern_return_t |
3220 | is_io_service_add_interest_notification_64( |
3221 | io_object_t service, |
3222 | io_name_t type_of_interest, |
3223 | mach_port_t wake_port, |
3224 | io_async_ref64_t reference, |
3225 | mach_msg_type_number_t referenceCnt, |
3226 | io_object_t *notification ) |
3227 | { |
3228 | io_async_ref64_t zreference; |
3229 | |
3230 | if (referenceCnt > ASYNC_REF64_COUNT) { |
3231 | return kIOReturnBadArgument; |
3232 | } |
3233 | bcopy(src: &reference[0], dst: &zreference[0], n: referenceCnt * sizeof(zreference[0])); |
3234 | bzero(s: &zreference[referenceCnt], n: (ASYNC_REF64_COUNT - referenceCnt) * sizeof(zreference[0])); |
3235 | |
3236 | return internal_io_service_add_interest_notification(service: service, type_of_interest, |
3237 | port: wake_port, reference: &zreference[0], referenceSize: sizeof(io_async_ref64_t), client64: true, notification); |
3238 | } |
3239 | |
3240 | |
3241 | /* Routine io_service_acknowledge_notification */ |
3242 | kern_return_t |
3243 | is_io_service_acknowledge_notification( |
3244 | io_object_t _service, |
3245 | natural_t notify_ref, |
3246 | natural_t response ) |
3247 | { |
3248 | CHECK( IOService, _service, service ); |
3249 | |
3250 | return service->acknowledgeNotification(notification: (IONotificationRef)(uintptr_t) notify_ref, |
3251 | response: (IOOptionBits) response ); |
3252 | } |
3253 | |
3254 | /* Routine io_connect_get_semaphore */ |
3255 | kern_return_t |
3256 | is_io_connect_get_notification_semaphore( |
3257 | io_connect_t connection, |
3258 | natural_t notification_type, |
3259 | semaphore_t *semaphore ) |
3260 | { |
3261 | IOReturn ret; |
3262 | CHECK( IOUserClient, connection, client ); |
3263 | |
3264 | IOStatisticsClientCall(); |
3265 | client->ipcEnter(locking: kIPCLockWrite); |
3266 | ret = client->getNotificationSemaphore(notification_type: (UInt32) notification_type, |
3267 | semaphore ); |
3268 | client->ipcExit(locking: kIPCLockWrite); |
3269 | |
3270 | return ret; |
3271 | } |
3272 | |
3273 | /* Routine io_registry_get_root_entry */ |
3274 | kern_return_t |
3275 | is_io_registry_get_root_entry( |
3276 | mach_port_t main_port, |
3277 | io_object_t *root ) |
3278 | { |
3279 | IORegistryEntry * entry; |
3280 | |
3281 | if (main_port != main_device_port) { |
3282 | return kIOReturnNotPrivileged; |
3283 | } |
3284 | |
3285 | entry = IORegistryEntry::getRegistryRoot(); |
3286 | if (entry) { |
3287 | entry->retain(); |
3288 | } |
3289 | *root = entry; |
3290 | |
3291 | return kIOReturnSuccess; |
3292 | } |
3293 | |
3294 | /* Routine io_registry_create_iterator */ |
3295 | kern_return_t |
3296 | is_io_registry_create_iterator( |
3297 | mach_port_t main_port, |
3298 | io_name_t plane, |
3299 | uint32_t options, |
3300 | io_object_t *iterator ) |
3301 | { |
3302 | if (main_port != main_device_port) { |
3303 | return kIOReturnNotPrivileged; |
3304 | } |
3305 | |
3306 | *iterator = IOUserIterator::withIterator( |
3307 | iter: IORegistryIterator::iterateOver( |
3308 | plane: IORegistryEntry::getPlane( name: plane ), options )); |
3309 | |
3310 | return *iterator ? kIOReturnSuccess : kIOReturnBadArgument; |
3311 | } |
3312 | |
3313 | /* Routine io_registry_entry_create_iterator */ |
3314 | kern_return_t |
3315 | is_io_registry_entry_create_iterator( |
3316 | io_object_t registry_entry, |
3317 | io_name_t plane, |
3318 | uint32_t options, |
3319 | io_object_t *iterator ) |
3320 | { |
3321 | CHECK( IORegistryEntry, registry_entry, entry ); |
3322 | |
3323 | *iterator = IOUserIterator::withIterator( |
3324 | iter: IORegistryIterator::iterateOver( start: entry, |
3325 | plane: IORegistryEntry::getPlane( name: plane ), options )); |
3326 | |
3327 | return *iterator ? kIOReturnSuccess : kIOReturnBadArgument; |
3328 | } |
3329 | |
3330 | /* Routine io_registry_iterator_enter */ |
3331 | kern_return_t |
3332 | is_io_registry_iterator_enter_entry( |
3333 | io_object_t iterator ) |
3334 | { |
3335 | CHECKLOCKED( IORegistryIterator, iterator, iter ); |
3336 | |
3337 | IOLockLock(&oIter->lock); |
3338 | iter->enterEntry(); |
3339 | IOLockUnlock(&oIter->lock); |
3340 | |
3341 | return kIOReturnSuccess; |
3342 | } |
3343 | |
3344 | /* Routine io_registry_iterator_exit */ |
3345 | kern_return_t |
3346 | is_io_registry_iterator_exit_entry( |
3347 | io_object_t iterator ) |
3348 | { |
3349 | bool didIt; |
3350 | |
3351 | CHECKLOCKED( IORegistryIterator, iterator, iter ); |
3352 | |
3353 | IOLockLock(&oIter->lock); |
3354 | didIt = iter->exitEntry(); |
3355 | IOLockUnlock(&oIter->lock); |
3356 | |
3357 | return didIt ? kIOReturnSuccess : kIOReturnNoDevice; |
3358 | } |
3359 | |
3360 | /* Routine io_registry_entry_from_path */ |
3361 | kern_return_t |
3362 | is_io_registry_entry_from_path( |
3363 | mach_port_t main_port, |
3364 | io_string_t path, |
3365 | io_object_t *registry_entry ) |
3366 | { |
3367 | IORegistryEntry * entry; |
3368 | |
3369 | if (main_port != main_device_port) { |
3370 | return kIOReturnNotPrivileged; |
3371 | } |
3372 | |
3373 | entry = IORegistryEntry::fromPath( path ); |
3374 | |
3375 | if (!entry && IOTaskRegistryCompatibility(task: current_task())) { |
3376 | OSDictionary * matching; |
3377 | const OSObject * objects[2] = { kOSBooleanTrue, NULL }; |
3378 | const OSSymbol * keys[2] = { gIOCompatibilityMatchKey, gIOPathMatchKey }; |
3379 | |
3380 | objects[1] = OSString::withCStringNoCopy(cString: path); |
3381 | matching = OSDictionary::withObjects(objects, keys, count: 2, capacity: 2); |
3382 | if (matching) { |
3383 | entry = IOService::copyMatchingService(matching); |
3384 | } |
3385 | OSSafeReleaseNULL(matching); |
3386 | OSSafeReleaseNULL(objects[1]); |
3387 | } |
3388 | |
3389 | *registry_entry = entry; |
3390 | |
3391 | return kIOReturnSuccess; |
3392 | } |
3393 | |
3394 | |
3395 | /* Routine io_registry_entry_from_path */ |
3396 | kern_return_t |
3397 | is_io_registry_entry_from_path_ool( |
3398 | mach_port_t main_port, |
3399 | io_string_inband_t path, |
3400 | io_buf_ptr_t path_ool, |
3401 | mach_msg_type_number_t path_oolCnt, |
3402 | kern_return_t *result, |
3403 | io_object_t *registry_entry) |
3404 | { |
3405 | IORegistryEntry * entry; |
3406 | vm_map_offset_t map_data; |
3407 | const char * cpath; |
3408 | IOReturn res; |
3409 | kern_return_t err; |
3410 | |
3411 | if (main_port != main_device_port) { |
3412 | return kIOReturnNotPrivileged; |
3413 | } |
3414 | |
3415 | map_data = 0; |
3416 | entry = NULL; |
3417 | res = err = KERN_SUCCESS; |
3418 | if (path[0]) { |
3419 | cpath = path; |
3420 | } else { |
3421 | if (!path_oolCnt) { |
3422 | return kIOReturnBadArgument; |
3423 | } |
3424 | if (path_oolCnt > (sizeof(io_struct_inband_t) * 1024)) { |
3425 | return kIOReturnMessageTooLarge; |
3426 | } |
3427 | |
3428 | err = vm_map_copyout(dst_map: kernel_map, dst_addr: &map_data, copy: (vm_map_copy_t) path_ool); |
3429 | if (KERN_SUCCESS == err) { |
3430 | // must return success to mig after vm_map_copyout() succeeds, so result is actual |
3431 | cpath = CAST_DOWN(const char *, map_data); |
3432 | if (cpath[path_oolCnt - 1]) { |
3433 | res = kIOReturnBadArgument; |
3434 | } |
3435 | } |
3436 | } |
3437 | |
3438 | if ((KERN_SUCCESS == err) && (KERN_SUCCESS == res)) { |
3439 | entry = IORegistryEntry::fromPath(path: cpath); |
3440 | res = entry ? kIOReturnSuccess : kIOReturnNotFound; |
3441 | } |
3442 | |
3443 | if (map_data) { |
3444 | vm_deallocate(target_task: kernel_map, address: map_data, size: path_oolCnt); |
3445 | } |
3446 | |
3447 | if (KERN_SUCCESS != err) { |
3448 | res = err; |
3449 | } |
3450 | *registry_entry = entry; |
3451 | *result = res; |
3452 | |
3453 | return err; |
3454 | } |
3455 | |
3456 | |
3457 | /* Routine io_registry_entry_in_plane */ |
3458 | kern_return_t |
3459 | is_io_registry_entry_in_plane( |
3460 | io_object_t registry_entry, |
3461 | io_name_t plane, |
3462 | boolean_t *inPlane ) |
3463 | { |
3464 | CHECK( IORegistryEntry, registry_entry, entry ); |
3465 | |
3466 | *inPlane = entry->inPlane( plane: IORegistryEntry::getPlane( name: plane )); |
3467 | |
3468 | return kIOReturnSuccess; |
3469 | } |
3470 | |
3471 | |
3472 | /* Routine io_registry_entry_get_path */ |
3473 | kern_return_t |
3474 | is_io_registry_entry_get_path( |
3475 | io_object_t registry_entry, |
3476 | io_name_t plane, |
3477 | io_string_t path ) |
3478 | { |
3479 | int length; |
3480 | CHECK( IORegistryEntry, registry_entry, entry ); |
3481 | |
3482 | length = sizeof(io_string_t); |
3483 | if (entry->getPath( path, length: &length, plane: IORegistryEntry::getPlane( name: plane ))) { |
3484 | return kIOReturnSuccess; |
3485 | } else { |
3486 | return kIOReturnBadArgument; |
3487 | } |
3488 | } |
3489 | |
3490 | /* Routine io_registry_entry_get_path */ |
3491 | kern_return_t |
3492 | is_io_registry_entry_get_path_ool( |
3493 | io_object_t registry_entry, |
3494 | io_name_t plane, |
3495 | io_string_inband_t path, |
3496 | io_buf_ptr_t *path_ool, |
3497 | mach_msg_type_number_t *path_oolCnt) |
3498 | { |
3499 | enum { kMaxPath = 16384 }; |
3500 | IOReturn err; |
3501 | int length; |
3502 | char * buf; |
3503 | |
3504 | CHECK( IORegistryEntry, registry_entry, entry ); |
3505 | |
3506 | *path_ool = NULL; |
3507 | *path_oolCnt = 0; |
3508 | length = sizeof(io_string_inband_t); |
3509 | if (entry->getPath(path, length: &length, plane: IORegistryEntry::getPlane(name: plane))) { |
3510 | err = kIOReturnSuccess; |
3511 | } else { |
3512 | length = kMaxPath; |
3513 | buf = IONewData(char, length); |
3514 | if (!buf) { |
3515 | err = kIOReturnNoMemory; |
3516 | } else if (!entry->getPath(path: buf, length: &length, plane: IORegistryEntry::getPlane(name: plane))) { |
3517 | err = kIOReturnError; |
3518 | } else { |
3519 | *path_oolCnt = length; |
3520 | err = copyoutkdata(data: buf, len: length, buf: path_ool); |
3521 | } |
3522 | if (buf) { |
3523 | IODeleteData(buf, char, kMaxPath); |
3524 | } |
3525 | } |
3526 | |
3527 | return err; |
3528 | } |
3529 | |
3530 | |
3531 | /* Routine io_registry_entry_get_name */ |
3532 | kern_return_t |
3533 | is_io_registry_entry_get_name( |
3534 | io_object_t registry_entry, |
3535 | io_name_t name ) |
3536 | { |
3537 | CHECK( IORegistryEntry, registry_entry, entry ); |
3538 | |
3539 | strncpy( name, entry->getName(), sizeof(io_name_t)); |
3540 | |
3541 | return kIOReturnSuccess; |
3542 | } |
3543 | |
3544 | /* Routine io_registry_entry_get_name_in_plane */ |
3545 | kern_return_t |
3546 | is_io_registry_entry_get_name_in_plane( |
3547 | io_object_t registry_entry, |
3548 | io_name_t planeName, |
3549 | io_name_t name ) |
3550 | { |
3551 | const IORegistryPlane * plane; |
3552 | CHECK( IORegistryEntry, registry_entry, entry ); |
3553 | |
3554 | if (planeName[0]) { |
3555 | plane = IORegistryEntry::getPlane( name: planeName ); |
3556 | } else { |
3557 | plane = NULL; |
3558 | } |
3559 | |
3560 | strncpy( name, entry->getName( plane), sizeof(io_name_t)); |
3561 | |
3562 | return kIOReturnSuccess; |
3563 | } |
3564 | |
3565 | /* Routine io_registry_entry_get_location_in_plane */ |
3566 | kern_return_t |
3567 | is_io_registry_entry_get_location_in_plane( |
3568 | io_object_t registry_entry, |
3569 | io_name_t planeName, |
3570 | io_name_t location ) |
3571 | { |
3572 | const IORegistryPlane * plane; |
3573 | CHECK( IORegistryEntry, registry_entry, entry ); |
3574 | |
3575 | if (planeName[0]) { |
3576 | plane = IORegistryEntry::getPlane( name: planeName ); |
3577 | } else { |
3578 | plane = NULL; |
3579 | } |
3580 | |
3581 | const char * cstr = entry->getLocation( plane ); |
3582 | |
3583 | if (cstr) { |
3584 | strncpy( location, cstr, sizeof(io_name_t)); |
3585 | return kIOReturnSuccess; |
3586 | } else { |
3587 | return kIOReturnNotFound; |
3588 | } |
3589 | } |
3590 | |
3591 | /* Routine io_registry_entry_get_registry_entry_id */ |
3592 | kern_return_t |
3593 | is_io_registry_entry_get_registry_entry_id( |
3594 | io_object_t registry_entry, |
3595 | uint64_t *entry_id ) |
3596 | { |
3597 | CHECK( IORegistryEntry, registry_entry, entry ); |
3598 | |
3599 | *entry_id = entry->getRegistryEntryID(); |
3600 | |
3601 | return kIOReturnSuccess; |
3602 | } |
3603 | |
3604 | |
3605 | static OSObject * |
3606 | IOCopyPropertyCompatible(IORegistryEntry * regEntry, const char * name) |
3607 | { |
3608 | OSObject * obj; |
3609 | OSObject * compatProperties; |
3610 | OSDictionary * props; |
3611 | |
3612 | obj = regEntry->copyProperty(aKey: name); |
3613 | if (obj) { |
3614 | return obj; |
3615 | } |
3616 | |
3617 | compatProperties = regEntry->copyProperty(aKey: gIOUserServicePropertiesKey); |
3618 | if (!compatProperties |
3619 | && IOTaskRegistryCompatibility(task: current_task())) { |
3620 | compatProperties = regEntry->copyProperty(aKey: gIOCompatibilityPropertiesKey); |
3621 | } |
3622 | if (compatProperties) { |
3623 | props = OSDynamicCast(OSDictionary, compatProperties); |
3624 | if (props) { |
3625 | obj = props->getObject(aKey: name); |
3626 | if (obj) { |
3627 | obj->retain(); |
3628 | } |
3629 | } |
3630 | compatProperties->release(); |
3631 | } |
3632 | |
3633 | return obj; |
3634 | } |
3635 | |
3636 | /* Routine io_registry_entry_get_property */ |
3637 | kern_return_t |
3638 | is_io_registry_entry_get_property_bytes( |
3639 | io_object_t registry_entry, |
3640 | io_name_t property_name, |
3641 | io_struct_inband_t buf, |
3642 | mach_msg_type_number_t *dataCnt ) |
3643 | { |
3644 | OSObject * obj; |
3645 | OSData * data; |
3646 | OSString * str; |
3647 | OSBoolean * boo; |
3648 | OSNumber * off; |
3649 | UInt64 offsetBytes; |
3650 | unsigned int len = 0; |
3651 | const void * bytes = NULL; |
3652 | IOReturn ret = kIOReturnSuccess; |
3653 | |
3654 | CHECK( IORegistryEntry, registry_entry, entry ); |
3655 | |
3656 | #if CONFIG_MACF |
3657 | if (0 != mac_iokit_check_get_property(cred: kauth_cred_get(), registry_entry: entry, name: property_name)) { |
3658 | return kIOReturnNotPermitted; |
3659 | } |
3660 | #endif |
3661 | |
3662 | obj = IOCopyPropertyCompatible(regEntry: entry, name: property_name); |
3663 | if (!obj) { |
3664 | return kIOReturnNoResources; |
3665 | } |
3666 | |
3667 | // One day OSData will be a common container base class |
3668 | // until then... |
3669 | if ((data = OSDynamicCast( OSData, obj ))) { |
3670 | len = data->getLength(); |
3671 | bytes = data->getBytesNoCopy(); |
3672 | if (!data->isSerializable()) { |
3673 | len = 0; |
3674 | } |
3675 | } else if ((str = OSDynamicCast( OSString, obj ))) { |
3676 | len = str->getLength() + 1; |
3677 | bytes = str->getCStringNoCopy(); |
3678 | } else if ((boo = OSDynamicCast( OSBoolean, obj ))) { |
3679 | len = boo->isTrue() ? sizeof("Yes" ) : sizeof("No" ); |
3680 | bytes = boo->isTrue() ? "Yes" : "No" ; |
3681 | } else if ((off = OSDynamicCast( OSNumber, obj ))) { |
3682 | offsetBytes = off->unsigned64BitValue(); |
3683 | len = off->numberOfBytes(); |
3684 | if (len > sizeof(offsetBytes)) { |
3685 | len = sizeof(offsetBytes); |
3686 | } |
3687 | bytes = &offsetBytes; |
3688 | #ifdef __BIG_ENDIAN__ |
3689 | bytes = (const void *) |
3690 | (((UInt32) bytes) + (sizeof(UInt64) - len)); |
3691 | #endif |
3692 | } else { |
3693 | ret = kIOReturnBadArgument; |
3694 | } |
3695 | |
3696 | if (bytes) { |
3697 | if (*dataCnt < len) { |
3698 | ret = kIOReturnIPCError; |
3699 | } else { |
3700 | *dataCnt = len; |
3701 | bcopy( src: bytes, dst: buf, n: len ); |
3702 | } |
3703 | } |
3704 | obj->release(); |
3705 | |
3706 | return ret; |
3707 | } |
3708 | |
3709 | |
3710 | /* Routine io_registry_entry_get_property */ |
3711 | kern_return_t |
3712 | is_io_registry_entry_get_property( |
3713 | io_object_t registry_entry, |
3714 | io_name_t property_name, |
3715 | io_buf_ptr_t *properties, |
3716 | mach_msg_type_number_t *propertiesCnt ) |
3717 | { |
3718 | kern_return_t err; |
3719 | unsigned int len; |
3720 | OSObject * obj; |
3721 | |
3722 | CHECK( IORegistryEntry, registry_entry, entry ); |
3723 | |
3724 | #if CONFIG_MACF |
3725 | if (0 != mac_iokit_check_get_property(cred: kauth_cred_get(), registry_entry: entry, name: property_name)) { |
3726 | return kIOReturnNotPermitted; |
3727 | } |
3728 | #endif |
3729 | |
3730 | obj = IOCopyPropertyCompatible(regEntry: entry, name: property_name); |
3731 | if (!obj) { |
3732 | return kIOReturnNotFound; |
3733 | } |
3734 | |
3735 | OSSerialize * s = OSSerialize::withCapacity(capacity: 4096); |
3736 | if (!s) { |
3737 | obj->release(); |
3738 | return kIOReturnNoMemory; |
3739 | } |
3740 | |
3741 | if (obj->serialize( serializer: s )) { |
3742 | len = s->getLength(); |
3743 | *propertiesCnt = len; |
3744 | err = copyoutkdata( data: s->text(), len, buf: properties ); |
3745 | } else { |
3746 | err = kIOReturnUnsupported; |
3747 | } |
3748 | |
3749 | s->release(); |
3750 | obj->release(); |
3751 | |
3752 | return err; |
3753 | } |
3754 | |
3755 | /* Routine io_registry_entry_get_property_recursively */ |
3756 | kern_return_t |
3757 | is_io_registry_entry_get_property_recursively( |
3758 | io_object_t registry_entry, |
3759 | io_name_t plane, |
3760 | io_name_t property_name, |
3761 | uint32_t options, |
3762 | io_buf_ptr_t *properties, |
3763 | mach_msg_type_number_t *propertiesCnt ) |
3764 | { |
3765 | kern_return_t err; |
3766 | unsigned int len; |
3767 | OSObject * obj; |
3768 | |
3769 | CHECK( IORegistryEntry, registry_entry, entry ); |
3770 | |
3771 | #if CONFIG_MACF |
3772 | if (0 != mac_iokit_check_get_property(cred: kauth_cred_get(), registry_entry: entry, name: property_name)) { |
3773 | return kIOReturnNotPermitted; |
3774 | } |
3775 | #endif |
3776 | |
3777 | obj = entry->copyProperty( aKey: property_name, |
3778 | plane: IORegistryEntry::getPlane( name: plane ), options ); |
3779 | if (!obj) { |
3780 | return kIOReturnNotFound; |
3781 | } |
3782 | |
3783 | OSSerialize * s = OSSerialize::withCapacity(capacity: 4096); |
3784 | if (!s) { |
3785 | obj->release(); |
3786 | return kIOReturnNoMemory; |
3787 | } |
3788 | |
3789 | if (obj->serialize( serializer: s )) { |
3790 | len = s->getLength(); |
3791 | *propertiesCnt = len; |
3792 | err = copyoutkdata( data: s->text(), len, buf: properties ); |
3793 | } else { |
3794 | err = kIOReturnUnsupported; |
3795 | } |
3796 | |
3797 | s->release(); |
3798 | obj->release(); |
3799 | |
3800 | return err; |
3801 | } |
3802 | |
3803 | /* Routine io_registry_entry_get_properties */ |
3804 | kern_return_t |
3805 | is_io_registry_entry_get_properties( |
3806 | io_object_t registry_entry, |
3807 | io_buf_ptr_t *properties, |
3808 | mach_msg_type_number_t *propertiesCnt ) |
3809 | { |
3810 | return kIOReturnUnsupported; |
3811 | } |
3812 | |
3813 | #if CONFIG_MACF |
3814 | |
3815 | struct GetPropertiesEditorRef { |
3816 | kauth_cred_t cred; |
3817 | IORegistryEntry * entry; |
3818 | OSCollection * root; |
3819 | }; |
3820 | |
3821 | static const LIBKERN_RETURNS_RETAINED OSMetaClassBase * |
3822 | GetPropertiesEditor(void * reference, |
3823 | OSSerialize * s, |
3824 | OSCollection * container, |
3825 | const OSSymbol * name, |
3826 | const OSMetaClassBase * value) |
3827 | { |
3828 | GetPropertiesEditorRef * ref = (typeof(ref))reference; |
3829 | |
3830 | if (!ref->root) { |
3831 | ref->root = container; |
3832 | } |
3833 | if (ref->root == container) { |
3834 | if (0 != mac_iokit_check_get_property(cred: ref->cred, registry_entry: ref->entry, name: name->getCStringNoCopy())) { |
3835 | value = NULL; |
3836 | } |
3837 | } |
3838 | if (value) { |
3839 | value->retain(); |
3840 | } |
3841 | return value; |
3842 | } |
3843 | |
3844 | #endif /* CONFIG_MACF */ |
3845 | |
3846 | /* Routine io_registry_entry_get_properties_bin_buf */ |
3847 | kern_return_t |
3848 | is_io_registry_entry_get_properties_bin_buf( |
3849 | io_object_t registry_entry, |
3850 | mach_vm_address_t buf, |
3851 | mach_vm_size_t *bufsize, |
3852 | io_buf_ptr_t *properties, |
3853 | mach_msg_type_number_t *propertiesCnt) |
3854 | { |
3855 | kern_return_t err = kIOReturnSuccess; |
3856 | unsigned int len; |
3857 | OSObject * compatProperties; |
3858 | OSSerialize * s; |
3859 | OSSerialize::Editor editor = NULL; |
3860 | void * editRef = NULL; |
3861 | |
3862 | CHECK(IORegistryEntry, registry_entry, entry); |
3863 | |
3864 | #if CONFIG_MACF |
3865 | GetPropertiesEditorRef ref; |
3866 | if (mac_iokit_check_filter_properties(cred: kauth_cred_get(), registry_entry: entry)) { |
3867 | editor = &GetPropertiesEditor; |
3868 | editRef = &ref; |
3869 | ref.cred = kauth_cred_get(); |
3870 | ref.entry = entry; |
3871 | ref.root = NULL; |
3872 | } |
3873 | #endif |
3874 | |
3875 | s = OSSerialize::binaryWithCapacity(inCapacity: 4096, editor, reference: editRef); |
3876 | if (!s) { |
3877 | return kIOReturnNoMemory; |
3878 | } |
3879 | |
3880 | |
3881 | compatProperties = entry->copyProperty(aKey: gIOUserServicePropertiesKey); |
3882 | if (!compatProperties |
3883 | && IOTaskRegistryCompatibility(task: current_task())) { |
3884 | compatProperties = entry->copyProperty(aKey: gIOCompatibilityPropertiesKey); |
3885 | } |
3886 | |
3887 | if (compatProperties) { |
3888 | OSDictionary * dict; |
3889 | |
3890 | dict = entry->dictionaryWithProperties(); |
3891 | if (!dict) { |
3892 | err = kIOReturnNoMemory; |
3893 | } else { |
3894 | dict->removeObject(aKey: gIOUserServicePropertiesKey); |
3895 | dict->removeObject(aKey: gIOCompatibilityPropertiesKey); |
3896 | dict->merge(OSDynamicCast(OSDictionary, compatProperties)); |
3897 | if (!dict->serialize(serializer: s)) { |
3898 | err = kIOReturnUnsupported; |
3899 | } |
3900 | dict->release(); |
3901 | } |
3902 | compatProperties->release(); |
3903 | } else if (!entry->serializeProperties(serialize: s)) { |
3904 | err = kIOReturnUnsupported; |
3905 | } |
3906 | |
3907 | if (kIOReturnSuccess == err) { |
3908 | len = s->getLength(); |
3909 | if (buf && bufsize && len <= *bufsize) { |
3910 | *bufsize = len; |
3911 | *propertiesCnt = 0; |
3912 | *properties = nullptr; |
3913 | if (copyout(s->text(), buf, len)) { |
3914 | err = kIOReturnVMError; |
3915 | } else { |
3916 | err = kIOReturnSuccess; |
3917 | } |
3918 | } else { |
3919 | if (bufsize) { |
3920 | *bufsize = 0; |
3921 | } |
3922 | *propertiesCnt = len; |
3923 | err = copyoutkdata( data: s->text(), len, buf: properties ); |
3924 | } |
3925 | } |
3926 | s->release(); |
3927 | |
3928 | return err; |
3929 | } |
3930 | |
3931 | /* Routine io_registry_entry_get_properties_bin */ |
3932 | kern_return_t |
3933 | is_io_registry_entry_get_properties_bin( |
3934 | io_object_t registry_entry, |
3935 | io_buf_ptr_t *properties, |
3936 | mach_msg_type_number_t *propertiesCnt) |
3937 | { |
3938 | return is_io_registry_entry_get_properties_bin_buf(registry_entry, |
3939 | buf: 0, NULL, properties, propertiesCnt); |
3940 | } |
3941 | |
3942 | /* Routine io_registry_entry_get_property_bin_buf */ |
3943 | kern_return_t |
3944 | is_io_registry_entry_get_property_bin_buf( |
3945 | io_object_t registry_entry, |
3946 | io_name_t plane, |
3947 | io_name_t property_name, |
3948 | uint32_t options, |
3949 | mach_vm_address_t buf, |
3950 | mach_vm_size_t *bufsize, |
3951 | io_buf_ptr_t *properties, |
3952 | mach_msg_type_number_t *propertiesCnt ) |
3953 | { |
3954 | kern_return_t err; |
3955 | unsigned int len; |
3956 | OSObject * obj; |
3957 | const OSSymbol * sym; |
3958 | |
3959 | CHECK( IORegistryEntry, registry_entry, entry ); |
3960 | |
3961 | #if CONFIG_MACF |
3962 | if (0 != mac_iokit_check_get_property(cred: kauth_cred_get(), registry_entry: entry, name: property_name)) { |
3963 | return kIOReturnNotPermitted; |
3964 | } |
3965 | #endif |
3966 | |
3967 | sym = OSSymbol::withCString(cString: property_name); |
3968 | if (!sym) { |
3969 | return kIOReturnNoMemory; |
3970 | } |
3971 | |
3972 | err = kIOReturnNotFound; |
3973 | if (gIORegistryEntryPropertyKeysKey == sym) { |
3974 | obj = entry->copyPropertyKeys(); |
3975 | } else { |
3976 | if ((kIORegistryIterateRecursively & options) && plane[0]) { |
3977 | obj = IOCopyPropertyCompatible(regEntry: entry, name: property_name); |
3978 | if (obj == NULL) { |
3979 | IORegistryIterator * iter = IORegistryIterator::iterateOver(start: entry, plane: IORegistryEntry::getPlane(name: plane), options); |
3980 | if (iter) { |
3981 | while ((NULL == obj) && (entry = iter->getNextObject())) { |
3982 | OSObject * currentObj = IOCopyPropertyCompatible(regEntry: entry, name: property_name); |
3983 | #if CONFIG_MACF |
3984 | if (currentObj != NULL && 0 != mac_iokit_check_get_property(cred: kauth_cred_get(), registry_entry: entry, name: property_name)) { |
3985 | // Record that MAC hook blocked this entry and property, and continue to next entry |
3986 | err = kIOReturnNotPermitted; |
3987 | OSSafeReleaseNULL(currentObj); |
3988 | continue; |
3989 | } |
3990 | #endif |
3991 | obj = currentObj; |
3992 | } |
3993 | iter->release(); |
3994 | } |
3995 | } |
3996 | } else { |
3997 | obj = IOCopyPropertyCompatible(regEntry: entry, name: property_name); |
3998 | } |
3999 | if (obj && gIORemoveOnReadProperties->containsObject(anObject: sym)) { |
4000 | entry->removeProperty(aKey: sym); |
4001 | } |
4002 | } |
4003 | |
4004 | sym->release(); |
4005 | if (!obj) { |
4006 | return err; |
4007 | } |
4008 | |
4009 | OSSerialize * s = OSSerialize::binaryWithCapacity(inCapacity: 4096); |
4010 | if (!s) { |
4011 | obj->release(); |
4012 | return kIOReturnNoMemory; |
4013 | } |
4014 | |
4015 | if (obj->serialize( serializer: s )) { |
4016 | len = s->getLength(); |
4017 | if (buf && bufsize && len <= *bufsize) { |
4018 | *bufsize = len; |
4019 | *propertiesCnt = 0; |
4020 | *properties = nullptr; |
4021 | if (copyout(s->text(), buf, len)) { |
4022 | err = kIOReturnVMError; |
4023 | } else { |
4024 | err = kIOReturnSuccess; |
4025 | } |
4026 | } else { |
4027 | if (bufsize) { |
4028 | *bufsize = 0; |
4029 | } |
4030 | *propertiesCnt = len; |
4031 | err = copyoutkdata( data: s->text(), len, buf: properties ); |
4032 | } |
4033 | } else { |
4034 | err = kIOReturnUnsupported; |
4035 | } |
4036 | |
4037 | s->release(); |
4038 | obj->release(); |
4039 | |
4040 | return err; |
4041 | } |
4042 | |
4043 | /* Routine io_registry_entry_get_property_bin */ |
4044 | kern_return_t |
4045 | is_io_registry_entry_get_property_bin( |
4046 | io_object_t registry_entry, |
4047 | io_name_t plane, |
4048 | io_name_t property_name, |
4049 | uint32_t options, |
4050 | io_buf_ptr_t *properties, |
4051 | mach_msg_type_number_t *propertiesCnt ) |
4052 | { |
4053 | return is_io_registry_entry_get_property_bin_buf(registry_entry, plane, |
4054 | property_name, options, buf: 0, NULL, properties, propertiesCnt); |
4055 | } |
4056 | |
4057 | |
4058 | /* Routine io_registry_entry_set_properties */ |
4059 | kern_return_t |
4060 | is_io_registry_entry_set_properties |
4061 | ( |
4062 | io_object_t registry_entry, |
4063 | io_buf_ptr_t properties, |
4064 | mach_msg_type_number_t propertiesCnt, |
4065 | kern_return_t * result) |
4066 | { |
4067 | OSObject * obj; |
4068 | kern_return_t err; |
4069 | IOReturn res; |
4070 | vm_offset_t data; |
4071 | vm_map_offset_t map_data; |
4072 | |
4073 | CHECK( IORegistryEntry, registry_entry, entry ); |
4074 | |
4075 | if (propertiesCnt > sizeof(io_struct_inband_t) * 1024) { |
4076 | return kIOReturnMessageTooLarge; |
4077 | } |
4078 | |
4079 | err = vm_map_copyout( dst_map: kernel_map, dst_addr: &map_data, copy: (vm_map_copy_t) properties ); |
4080 | data = CAST_DOWN(vm_offset_t, map_data); |
4081 | |
4082 | if (KERN_SUCCESS == err) { |
4083 | FAKE_STACK_FRAME(entry->getMetaClass()); |
4084 | |
4085 | // must return success after vm_map_copyout() succeeds |
4086 | obj = OSUnserializeXML(buffer: (const char *) data, bufferSize: propertiesCnt ); |
4087 | vm_deallocate( target_task: kernel_map, address: data, size: propertiesCnt ); |
4088 | |
4089 | if (!obj) { |
4090 | res = kIOReturnBadArgument; |
4091 | } |
4092 | #if CONFIG_MACF |
4093 | else if (0 != mac_iokit_check_set_properties(cred: kauth_cred_get(), |
4094 | registry_entry, properties: obj)) { |
4095 | res = kIOReturnNotPermitted; |
4096 | } |
4097 | #endif |
4098 | else { |
4099 | IOService * service = OSDynamicCast(IOService, entry); |
4100 | OSDictionary * props = OSDynamicCast(OSDictionary, obj); |
4101 | OSObject * allowable = entry->copyProperty(aKey: gIORegistryEntryAllowableSetPropertiesKey); |
4102 | OSArray * allowableArray; |
4103 | |
4104 | if (!allowable) { |
4105 | res = kIOReturnSuccess; |
4106 | } else { |
4107 | if (!props) { |
4108 | res = kIOReturnNotPermitted; |
4109 | } else if (!(allowableArray = OSDynamicCast(OSArray, allowable))) { |
4110 | res = kIOReturnNotPermitted; |
4111 | } else { |
4112 | bool allFound __block, found __block; |
4113 | |
4114 | allFound = true; |
4115 | props->iterateObjects(block: ^(const OSSymbol * key, OSObject * value) { |
4116 | found = false; |
4117 | for (unsigned int idx = 0; !found; idx++) { |
4118 | OSObject * next = allowableArray->getObject(index: idx); |
4119 | if (!next) { |
4120 | break; |
4121 | } |
4122 | found = next->isEqualTo(anObject: key); |
4123 | } |
4124 | allFound &= found; |
4125 | if (!found) { |
4126 | IOLog(format: "IORegistryEntrySetProperties(%s, %s) disallowed due to " kIORegistryEntryAllowableSetPropertiesKey "\n" , |
4127 | entry->getName(), key->getCStringNoCopy()); |
4128 | } |
4129 | return !allFound; |
4130 | }); |
4131 | res = allFound ? kIOReturnSuccess : kIOReturnBadArgument; |
4132 | } |
4133 | } |
4134 | if (kIOReturnSuccess == res) { |
4135 | IOUserClient * |
4136 | client = OSDynamicCast(IOUserClient, entry); |
4137 | |
4138 | if (client && client->defaultLockingSetProperties) { |
4139 | IORWLockWrite(&client->lock); |
4140 | } |
4141 | |
4142 | if (!client && (kOSBooleanTrue == entry->getProperty(aKey: gIORegistryEntryDefaultLockingSetPropertiesKey))) { |
4143 | res = entry->runPropertyActionBlock(block: ^IOReturn (void) { |
4144 | return entry->setProperties( obj ); |
4145 | }); |
4146 | } else { |
4147 | res = entry->setProperties( obj ); |
4148 | } |
4149 | |
4150 | if (client && client->defaultLockingSetProperties) { |
4151 | IORWLockUnlock(&client->lock); |
4152 | } |
4153 | if (service && props && service->hasUserServer()) { |
4154 | res = service->UserSetProperties(properties: props); |
4155 | } |
4156 | } |
4157 | OSSafeReleaseNULL(allowable); |
4158 | } |
4159 | if (obj) { |
4160 | obj->release(); |
4161 | } |
4162 | |
4163 | FAKE_STACK_FRAME_END(); |
4164 | } else { |
4165 | res = err; |
4166 | } |
4167 | |
4168 | *result = res; |
4169 | return err; |
4170 | } |
4171 | |
4172 | /* Routine io_registry_entry_get_child_iterator */ |
4173 | kern_return_t |
4174 | is_io_registry_entry_get_child_iterator( |
4175 | io_object_t registry_entry, |
4176 | io_name_t plane, |
4177 | io_object_t *iterator ) |
4178 | { |
4179 | CHECK( IORegistryEntry, registry_entry, entry ); |
4180 | |
4181 | *iterator = IOUserIterator::withIterator(iter: entry->getChildIterator( |
4182 | plane: IORegistryEntry::getPlane( name: plane ))); |
4183 | |
4184 | return kIOReturnSuccess; |
4185 | } |
4186 | |
4187 | /* Routine io_registry_entry_get_parent_iterator */ |
4188 | kern_return_t |
4189 | is_io_registry_entry_get_parent_iterator( |
4190 | io_object_t registry_entry, |
4191 | io_name_t plane, |
4192 | io_object_t *iterator) |
4193 | { |
4194 | CHECK( IORegistryEntry, registry_entry, entry ); |
4195 | |
4196 | *iterator = IOUserIterator::withIterator(iter: entry->getParentIterator( |
4197 | plane: IORegistryEntry::getPlane( name: plane ))); |
4198 | |
4199 | return kIOReturnSuccess; |
4200 | } |
4201 | |
4202 | /* Routine io_service_get_busy_state */ |
4203 | kern_return_t |
4204 | is_io_service_get_busy_state( |
4205 | io_object_t _service, |
4206 | uint32_t *busyState ) |
4207 | { |
4208 | CHECK( IOService, _service, service ); |
4209 | |
4210 | *busyState = service->getBusyState(); |
4211 | |
4212 | return kIOReturnSuccess; |
4213 | } |
4214 | |
4215 | /* Routine io_service_get_state */ |
4216 | kern_return_t |
4217 | is_io_service_get_state( |
4218 | io_object_t _service, |
4219 | uint64_t *state, |
4220 | uint32_t *busy_state, |
4221 | uint64_t *accumulated_busy_time ) |
4222 | { |
4223 | CHECK( IOService, _service, service ); |
4224 | |
4225 | *state = service->getState(); |
4226 | *busy_state = service->getBusyState(); |
4227 | *accumulated_busy_time = service->getAccumulatedBusyTime(); |
4228 | |
4229 | return kIOReturnSuccess; |
4230 | } |
4231 | |
4232 | /* Routine io_service_wait_quiet */ |
4233 | kern_return_t |
4234 | is_io_service_wait_quiet( |
4235 | io_object_t _service, |
4236 | mach_timespec_t wait_time ) |
4237 | { |
4238 | uint64_t timeoutNS; |
4239 | |
4240 | CHECK( IOService, _service, service ); |
4241 | |
4242 | timeoutNS = wait_time.tv_sec; |
4243 | timeoutNS *= kSecondScale; |
4244 | timeoutNS += wait_time.tv_nsec; |
4245 | |
4246 | return service->waitQuiet(timeout: timeoutNS); |
4247 | } |
4248 | |
4249 | /* Routine io_service_wait_quiet_with_options */ |
4250 | kern_return_t |
4251 | is_io_service_wait_quiet_with_options( |
4252 | io_object_t _service, |
4253 | mach_timespec_t wait_time, |
4254 | uint32_t options ) |
4255 | { |
4256 | uint64_t timeoutNS; |
4257 | |
4258 | CHECK( IOService, _service, service ); |
4259 | |
4260 | timeoutNS = wait_time.tv_sec; |
4261 | timeoutNS *= kSecondScale; |
4262 | timeoutNS += wait_time.tv_nsec; |
4263 | |
4264 | if ((options & kIOWaitQuietPanicOnFailure) && !IOCurrentTaskHasEntitlement(kIOWaitQuietPanicsEntitlement)) { |
4265 | OSString * taskName = IOCopyLogNameForPID(pid: proc_selfpid()); |
4266 | IOLog(format: "IOServiceWaitQuietWithOptions(%s): Not entitled\n" , taskName ? taskName->getCStringNoCopy() : "" ); |
4267 | OSSafeReleaseNULL(taskName); |
4268 | |
4269 | /* strip this option from the options before calling waitQuietWithOptions */ |
4270 | options &= ~kIOWaitQuietPanicOnFailure; |
4271 | } |
4272 | |
4273 | return service->waitQuietWithOptions(timeout: timeoutNS, options); |
4274 | } |
4275 | |
4276 | |
4277 | /* Routine io_service_request_probe */ |
4278 | kern_return_t |
4279 | is_io_service_request_probe( |
4280 | io_object_t _service, |
4281 | uint32_t options ) |
4282 | { |
4283 | CHECK( IOService, _service, service ); |
4284 | |
4285 | return service->requestProbe( options ); |
4286 | } |
4287 | |
4288 | /* Routine io_service_get_authorization_id */ |
4289 | kern_return_t |
4290 | is_io_service_get_authorization_id( |
4291 | io_object_t _service, |
4292 | uint64_t *authorization_id ) |
4293 | { |
4294 | kern_return_t kr; |
4295 | |
4296 | CHECK( IOService, _service, service ); |
4297 | |
4298 | kr = IOUserClient::clientHasPrivilege(securityToken: (void *) current_task(), |
4299 | kIOClientPrivilegeAdministrator ); |
4300 | if (kIOReturnSuccess != kr) { |
4301 | return kr; |
4302 | } |
4303 | |
4304 | #if defined(XNU_TARGET_OS_OSX) |
4305 | *authorization_id = service->getAuthorizationID(); |
4306 | #else /* defined(XNU_TARGET_OS_OSX) */ |
4307 | *authorization_id = 0; |
4308 | kr = kIOReturnUnsupported; |
4309 | #endif /* defined(XNU_TARGET_OS_OSX) */ |
4310 | |
4311 | return kr; |
4312 | } |
4313 | |
4314 | /* Routine io_service_set_authorization_id */ |
4315 | kern_return_t |
4316 | is_io_service_set_authorization_id( |
4317 | io_object_t _service, |
4318 | uint64_t authorization_id ) |
4319 | { |
4320 | CHECK( IOService, _service, service ); |
4321 | |
4322 | #if defined(XNU_TARGET_OS_OSX) |
4323 | return service->setAuthorizationID( authorization_id ); |
4324 | #else /* defined(XNU_TARGET_OS_OSX) */ |
4325 | return kIOReturnUnsupported; |
4326 | #endif /* defined(XNU_TARGET_OS_OSX) */ |
4327 | } |
4328 | |
4329 | /* Routine io_service_open_ndr */ |
4330 | kern_return_t |
4331 | is_io_service_open_extended( |
4332 | io_object_t _service, |
4333 | task_t owningTask, |
4334 | uint32_t connect_type, |
4335 | NDR_record_t ndr, |
4336 | io_buf_ptr_t properties, |
4337 | mach_msg_type_number_t propertiesCnt, |
4338 | kern_return_t * result, |
4339 | io_object_t *connection ) |
4340 | { |
4341 | IOUserClient * client = NULL; |
4342 | kern_return_t err = KERN_SUCCESS; |
4343 | IOReturn res = kIOReturnSuccess; |
4344 | OSDictionary * propertiesDict = NULL; |
4345 | bool disallowAccess = false; |
4346 | |
4347 | CHECK( IOService, _service, service ); |
4348 | |
4349 | if (!owningTask) { |
4350 | return kIOReturnBadArgument; |
4351 | } |
4352 | assert(owningTask == current_task()); |
4353 | if (owningTask != current_task()) { |
4354 | return kIOReturnBadArgument; |
4355 | } |
4356 | |
4357 | #if CONFIG_MACF |
4358 | if (mac_iokit_check_open_service(cred: kauth_cred_get(), service, user_client_type: connect_type) != 0) { |
4359 | return kIOReturnNotPermitted; |
4360 | } |
4361 | #endif |
4362 | do{ |
4363 | if (properties) { |
4364 | return kIOReturnUnsupported; |
4365 | } |
4366 | #if 0 |
4367 | { |
4368 | OSObject * obj; |
4369 | vm_offset_t data; |
4370 | vm_map_offset_t map_data; |
4371 | |
4372 | if (propertiesCnt > sizeof(io_struct_inband_t)) { |
4373 | return kIOReturnMessageTooLarge; |
4374 | } |
4375 | |
4376 | err = vm_map_copyout( kernel_map, &map_data, (vm_map_copy_t) properties ); |
4377 | res = err; |
4378 | data = CAST_DOWN(vm_offset_t, map_data); |
4379 | if (KERN_SUCCESS == err) { |
4380 | // must return success after vm_map_copyout() succeeds |
4381 | obj = OSUnserializeXML((const char *) data, propertiesCnt ); |
4382 | vm_deallocate( kernel_map, data, propertiesCnt ); |
4383 | propertiesDict = OSDynamicCast(OSDictionary, obj); |
4384 | if (!propertiesDict) { |
4385 | res = kIOReturnBadArgument; |
4386 | if (obj) { |
4387 | obj->release(); |
4388 | } |
4389 | } |
4390 | } |
4391 | if (kIOReturnSuccess != res) { |
4392 | break; |
4393 | } |
4394 | } |
4395 | #endif |
4396 | res = service->newUserClient( owningTask, securityID: (void *) owningTask, |
4397 | type: connect_type, properties: propertiesDict, handler: &client ); |
4398 | |
4399 | if (propertiesDict) { |
4400 | propertiesDict->release(); |
4401 | } |
4402 | |
4403 | if (res == kIOReturnSuccess && OSDynamicCast(IOUserClient, client) == NULL) { |
4404 | // client should always be a IOUserClient |
4405 | res = kIOReturnError; |
4406 | } |
4407 | |
4408 | if (res == kIOReturnSuccess) { |
4409 | if (!client->reserved) { |
4410 | if (!client->reserve()) { |
4411 | client->clientClose(); |
4412 | OSSafeReleaseNULL(client); |
4413 | res = kIOReturnNoMemory; |
4414 | } |
4415 | } |
4416 | } |
4417 | |
4418 | if (res == kIOReturnSuccess) { |
4419 | OSString * creatorName = IOCopyLogNameForPID(pid: proc_selfpid()); |
4420 | if (creatorName) { |
4421 | client->setProperty(kIOUserClientCreatorKey, anObject: creatorName); |
4422 | } |
4423 | const char * creatorNameCStr = creatorName ? creatorName->getCStringNoCopy() : "<unknown>" ; |
4424 | client->sharedInstance = (NULL != client->getProperty(kIOUserClientSharedInstanceKey)); |
4425 | if (client->sharedInstance) { |
4426 | IOLockLock(gIOUserClientOwnersLock); |
4427 | } |
4428 | if (!client->opened) { |
4429 | client->opened = true; |
4430 | |
4431 | client->messageAppSuspended = (NULL != client->getProperty(kIOUserClientMessageAppSuspendedKey)); |
4432 | { |
4433 | OSObject * obj; |
4434 | extern const OSSymbol * gIOSurfaceIdentifier; |
4435 | obj = client->getProperty(kIOUserClientDefaultLockingKey); |
4436 | bool hasProps = false; |
4437 | |
4438 | client->uc2022 = (NULL != OSDynamicCast(IOUserClient2022, client)); |
4439 | if (obj) { |
4440 | hasProps = true; |
4441 | client->defaultLocking = (kOSBooleanFalse != client->getProperty(kIOUserClientDefaultLockingKey)); |
4442 | } else if (client->uc2022) { |
4443 | res = kIOReturnError; |
4444 | } |
4445 | obj = client->getProperty(kIOUserClientDefaultLockingSetPropertiesKey); |
4446 | if (obj) { |
4447 | hasProps = true; |
4448 | client->defaultLockingSetProperties = (kOSBooleanFalse != client->getProperty(kIOUserClientDefaultLockingSetPropertiesKey)); |
4449 | } else if (client->uc2022) { |
4450 | res = kIOReturnError; |
4451 | } |
4452 | obj = client->getProperty(kIOUserClientDefaultLockingSingleThreadExternalMethodKey); |
4453 | if (obj) { |
4454 | hasProps = true; |
4455 | client->defaultLockingSingleThreadExternalMethod = (kOSBooleanFalse != client->getProperty(kIOUserClientDefaultLockingSingleThreadExternalMethodKey)); |
4456 | } else if (client->uc2022) { |
4457 | res = kIOReturnError; |
4458 | } |
4459 | if (kIOReturnSuccess != res) { |
4460 | IOLog(format: "IOUC %s requires kIOUserClientDefaultLockingKey, kIOUserClientDefaultLockingSetPropertiesKey, kIOUserClientDefaultLockingSingleThreadExternalMethodKey\n" , |
4461 | client->getMetaClass()->getClassName()); |
4462 | } |
4463 | if (!hasProps) { |
4464 | const OSMetaClass * meta; |
4465 | OSKext * kext; |
4466 | meta = client->getMetaClass(); |
4467 | kext = meta->getKext(); |
4468 | if (!kext || !kext->hasDependency(depID: gIOSurfaceIdentifier)) { |
4469 | client->defaultLocking = true; |
4470 | client->defaultLockingSetProperties = false; |
4471 | client->defaultLockingSingleThreadExternalMethod = false; |
4472 | client->setProperty(kIOUserClientDefaultLockingKey, anObject: kOSBooleanTrue); |
4473 | } |
4474 | } |
4475 | } |
4476 | } |
4477 | if (client->sharedInstance) { |
4478 | IOLockUnlock(gIOUserClientOwnersLock); |
4479 | } |
4480 | |
4481 | OSObject * requiredEntitlement = client->copyProperty(aKey: gIOUserClientEntitlementsKey); |
4482 | OSString * requiredEntitlementString = OSDynamicCast(OSString, requiredEntitlement); |
4483 | //If this is an IOUserClient2022, having kIOUserClientEntitlementsKey is mandatory. |
4484 | //If it has kIOUserClientEntitlementsKey, the value must be either kOSBooleanFalse or an OSString |
4485 | //If the value is kOSBooleanFalse, we allow access. |
4486 | //If the value is an OSString, we allow access if the task has the named entitlement |
4487 | if (client->uc2022) { |
4488 | if (!requiredEntitlement) { |
4489 | IOLog(format: "IOUC %s missing " kIOUserClientEntitlementsKey " property\n" , |
4490 | client->getMetaClass()->getClassName()); |
4491 | disallowAccess = true; |
4492 | } else if (!requiredEntitlementString && requiredEntitlement != kOSBooleanFalse) { |
4493 | IOLog(format: "IOUC %s had " kIOUserClientEntitlementsKey "with value not boolean false or string\n" , client->getMetaClass()->getClassName()); |
4494 | disallowAccess = true; |
4495 | } |
4496 | } |
4497 | |
4498 | if (requiredEntitlement && disallowAccess == false) { |
4499 | if (kOSBooleanFalse == requiredEntitlement) { |
4500 | // allow |
4501 | disallowAccess = false; |
4502 | } else { |
4503 | disallowAccess = !IOTaskHasEntitlement(task: owningTask, entitlement: requiredEntitlementString->getCStringNoCopy()); |
4504 | if (disallowAccess) { |
4505 | IOLog(format: "IOUC %s missing entitlement in process %s\n" , |
4506 | client->getMetaClass()->getClassName(), creatorNameCStr); |
4507 | } |
4508 | } |
4509 | } |
4510 | |
4511 | OSSafeReleaseNULL(requiredEntitlement); |
4512 | |
4513 | if (disallowAccess) { |
4514 | res = kIOReturnNotPrivileged; |
4515 | } |
4516 | #if CONFIG_MACF |
4517 | else if (0 != mac_iokit_check_open(cred: kauth_cred_get(), user_client: client, user_client_type: connect_type)) { |
4518 | IOLog(format: "IOUC %s failed MACF in process %s\n" , |
4519 | client->getMetaClass()->getClassName(), creatorNameCStr); |
4520 | res = kIOReturnNotPermitted; |
4521 | } |
4522 | #endif |
4523 | |
4524 | if ((kIOReturnSuccess == res) |
4525 | && gIOUCFilterCallbacks |
4526 | && gIOUCFilterCallbacks->io_filter_resolver) { |
4527 | io_filter_policy_t filterPolicy; |
4528 | filterPolicy = client->filterForTask(task: owningTask, addFilterPolicy: 0); |
4529 | if (!filterPolicy) { |
4530 | res = gIOUCFilterCallbacks->io_filter_resolver(owningTask, client, connect_type, &filterPolicy); |
4531 | if (kIOReturnUnsupported == res) { |
4532 | res = kIOReturnSuccess; |
4533 | } else if (kIOReturnSuccess == res) { |
4534 | client->filterForTask(task: owningTask, addFilterPolicy: filterPolicy); |
4535 | } else { |
4536 | IOLog(format: "IOUC %s failed sandbox in process %s\n" , |
4537 | client->getMetaClass()->getClassName(), creatorNameCStr); |
4538 | } |
4539 | } |
4540 | } |
4541 | |
4542 | if (kIOReturnSuccess == res) { |
4543 | res = client->registerOwner(task: owningTask); |
4544 | } |
4545 | OSSafeReleaseNULL(creatorName); |
4546 | |
4547 | if (kIOReturnSuccess != res) { |
4548 | IOStatisticsClientCall(); |
4549 | client->clientClose(); |
4550 | client->setTerminateDefer(provider: service, defer: false); |
4551 | client->release(); |
4552 | client = NULL; |
4553 | break; |
4554 | } |
4555 | client->setTerminateDefer(provider: service, defer: false); |
4556 | } |
4557 | }while (false); |
4558 | |
4559 | *connection = client; |
4560 | *result = res; |
4561 | |
4562 | return err; |
4563 | } |
4564 | |
4565 | /* Routine io_service_close */ |
4566 | kern_return_t |
4567 | is_io_service_close( |
4568 | io_connect_t connection ) |
4569 | { |
4570 | OSSet * mappings; |
4571 | if ((mappings = OSDynamicCast(OSSet, connection))) { |
4572 | return kIOReturnSuccess; |
4573 | } |
4574 | |
4575 | CHECK( IOUserClient, connection, client ); |
4576 | |
4577 | IOStatisticsClientCall(); |
4578 | |
4579 | if (client->sharedInstance || OSCompareAndSwap8(0, 1, &client->closed)) { |
4580 | client->ipcEnter(locking: kIPCLockWrite); |
4581 | client->clientClose(); |
4582 | client->ipcExit(locking: kIPCLockWrite); |
4583 | } else { |
4584 | IOLog(format: "ignored is_io_service_close(0x%qx,%s)\n" , |
4585 | client->getRegistryEntryID(), client->getName()); |
4586 | } |
4587 | |
4588 | return kIOReturnSuccess; |
4589 | } |
4590 | |
4591 | /* Routine io_connect_get_service */ |
4592 | kern_return_t |
4593 | is_io_connect_get_service( |
4594 | io_connect_t connection, |
4595 | io_object_t *service ) |
4596 | { |
4597 | IOService * theService; |
4598 | |
4599 | CHECK( IOUserClient, connection, client ); |
4600 | |
4601 | client->ipcEnter(locking: kIPCLockNone); |
4602 | |
4603 | theService = client->getService(); |
4604 | if (theService) { |
4605 | theService->retain(); |
4606 | } |
4607 | |
4608 | client->ipcExit(locking: kIPCLockNone); |
4609 | |
4610 | *service = theService; |
4611 | |
4612 | return theService ? kIOReturnSuccess : kIOReturnUnsupported; |
4613 | } |
4614 | |
4615 | /* Routine io_connect_set_notification_port */ |
4616 | kern_return_t |
4617 | is_io_connect_set_notification_port( |
4618 | io_connect_t connection, |
4619 | uint32_t notification_type, |
4620 | mach_port_t port, |
4621 | uint32_t reference) |
4622 | { |
4623 | kern_return_t ret; |
4624 | CHECK( IOUserClient, connection, client ); |
4625 | |
4626 | IOStatisticsClientCall(); |
4627 | |
4628 | client->ipcEnter(locking: kIPCLockWrite); |
4629 | ret = client->registerNotificationPort( port, type: notification_type, |
4630 | refCon: (io_user_reference_t) reference ); |
4631 | client->ipcExit(locking: kIPCLockWrite); |
4632 | |
4633 | return ret; |
4634 | } |
4635 | |
4636 | /* Routine io_connect_set_notification_port */ |
4637 | kern_return_t |
4638 | is_io_connect_set_notification_port_64( |
4639 | io_connect_t connection, |
4640 | uint32_t notification_type, |
4641 | mach_port_t port, |
4642 | io_user_reference_t reference) |
4643 | { |
4644 | kern_return_t ret; |
4645 | CHECK( IOUserClient, connection, client ); |
4646 | |
4647 | IOStatisticsClientCall(); |
4648 | |
4649 | client->ipcEnter(locking: kIPCLockWrite); |
4650 | ret = client->registerNotificationPort( port, type: notification_type, |
4651 | refCon: reference ); |
4652 | client->ipcExit(locking: kIPCLockWrite); |
4653 | |
4654 | return ret; |
4655 | } |
4656 | |
4657 | /* Routine io_connect_map_memory_into_task */ |
4658 | kern_return_t |
4659 | is_io_connect_map_memory_into_task |
4660 | ( |
4661 | io_connect_t connection, |
4662 | uint32_t memory_type, |
4663 | task_t into_task, |
4664 | mach_vm_address_t *address, |
4665 | mach_vm_size_t *size, |
4666 | uint32_t flags |
4667 | ) |
4668 | { |
4669 | IOReturn err; |
4670 | IOMemoryMap * map; |
4671 | |
4672 | CHECK( IOUserClient, connection, client ); |
4673 | |
4674 | if (!into_task) { |
4675 | return kIOReturnBadArgument; |
4676 | } |
4677 | |
4678 | IOStatisticsClientCall(); |
4679 | |
4680 | client->ipcEnter(locking: client->defaultLocking ? kIPCLockWrite : kIPCLockNone); |
4681 | map = client->mapClientMemory64( type: memory_type, task: into_task, mapFlags: flags, atAddress: *address ); |
4682 | |
4683 | if (map) { |
4684 | *address = map->getAddress(); |
4685 | if (size) { |
4686 | *size = map->getSize(); |
4687 | } |
4688 | |
4689 | if (client->sharedInstance |
4690 | || (into_task != current_task())) { |
4691 | // push a name out to the task owning the map, |
4692 | // so we can clean up maps |
4693 | mach_port_name_t name __unused = |
4694 | IOMachPort::makeSendRightForTask( |
4695 | task: into_task, obj: map, type: IKOT_IOKIT_OBJECT ); |
4696 | map->release(); |
4697 | } else { |
4698 | // keep it with the user client |
4699 | IOLockLock( gIOObjectPortLock); |
4700 | if (NULL == client->mappings) { |
4701 | client->mappings = OSSet::withCapacity(capacity: 2); |
4702 | } |
4703 | if (client->mappings) { |
4704 | client->mappings->setObject( map); |
4705 | } |
4706 | IOLockUnlock( gIOObjectPortLock); |
4707 | map->release(); |
4708 | } |
4709 | err = kIOReturnSuccess; |
4710 | } else { |
4711 | err = kIOReturnBadArgument; |
4712 | } |
4713 | |
4714 | client->ipcExit(locking: client->defaultLocking ? kIPCLockWrite : kIPCLockNone); |
4715 | |
4716 | return err; |
4717 | } |
4718 | |
4719 | /* Routine is_io_connect_map_memory */ |
4720 | kern_return_t |
4721 | is_io_connect_map_memory( |
4722 | io_object_t connect, |
4723 | uint32_t type, |
4724 | task_t task, |
4725 | uint32_t * mapAddr, |
4726 | uint32_t * mapSize, |
4727 | uint32_t flags ) |
4728 | { |
4729 | IOReturn err; |
4730 | mach_vm_address_t address; |
4731 | mach_vm_size_t size; |
4732 | |
4733 | address = SCALAR64(*mapAddr); |
4734 | size = SCALAR64(*mapSize); |
4735 | |
4736 | err = is_io_connect_map_memory_into_task(connection: connect, memory_type: type, into_task: task, address: &address, size: &size, flags); |
4737 | |
4738 | *mapAddr = SCALAR32(address); |
4739 | *mapSize = SCALAR32(size); |
4740 | |
4741 | return err; |
4742 | } |
4743 | } /* extern "C" */ |
4744 | |
4745 | IOMemoryMap * |
4746 | IOUserClient::removeMappingForDescriptor(IOMemoryDescriptor * mem) |
4747 | { |
4748 | OSIterator * iter; |
4749 | IOMemoryMap * map = NULL; |
4750 | |
4751 | IOLockLock(gIOObjectPortLock); |
4752 | |
4753 | iter = OSCollectionIterator::withCollection(inColl: mappings); |
4754 | if (iter) { |
4755 | while ((map = OSDynamicCast(IOMemoryMap, iter->getNextObject()))) { |
4756 | if (mem == map->getMemoryDescriptor()) { |
4757 | map->retain(); |
4758 | mappings->removeObject(anObject: map); |
4759 | break; |
4760 | } |
4761 | } |
4762 | iter->release(); |
4763 | } |
4764 | |
4765 | IOLockUnlock(gIOObjectPortLock); |
4766 | |
4767 | return map; |
4768 | } |
4769 | |
4770 | extern "C" { |
4771 | /* Routine io_connect_unmap_memory_from_task */ |
4772 | kern_return_t |
4773 | is_io_connect_unmap_memory_from_task |
4774 | ( |
4775 | io_connect_t connection, |
4776 | uint32_t memory_type, |
4777 | task_t from_task, |
4778 | mach_vm_address_t address) |
4779 | { |
4780 | IOReturn err; |
4781 | IOOptionBits options = 0; |
4782 | IOMemoryDescriptor * memory = NULL; |
4783 | IOMemoryMap * map; |
4784 | |
4785 | CHECK( IOUserClient, connection, client ); |
4786 | |
4787 | if (!from_task) { |
4788 | return kIOReturnBadArgument; |
4789 | } |
4790 | |
4791 | IOStatisticsClientCall(); |
4792 | |
4793 | client->ipcEnter(locking: client->defaultLocking ? kIPCLockWrite : kIPCLockNone); |
4794 | err = client->clientMemoryForType(type: (UInt32) memory_type, options: &options, memory: &memory ); |
4795 | |
4796 | if (memory && (kIOReturnSuccess == err)) { |
4797 | options = (options & ~kIOMapUserOptionsMask) |
4798 | | kIOMapAnywhere | kIOMapReference; |
4799 | |
4800 | map = memory->createMappingInTask( intoTask: from_task, atAddress: address, options ); |
4801 | memory->release(); |
4802 | if (map) { |
4803 | IOLockLock( gIOObjectPortLock); |
4804 | if (client->mappings) { |
4805 | client->mappings->removeObject( anObject: map); |
4806 | } |
4807 | IOLockUnlock( gIOObjectPortLock); |
4808 | |
4809 | mach_port_name_t name = 0; |
4810 | bool is_shared_instance_or_from_current_task = from_task != current_task() || client->sharedInstance; |
4811 | if (is_shared_instance_or_from_current_task) { |
4812 | name = IOMachPort::makeSendRightForTask( task: from_task, obj: map, type: IKOT_IOKIT_OBJECT ); |
4813 | map->release(); |
4814 | } |
4815 | |
4816 | if (name) { |
4817 | map->userClientUnmap(); |
4818 | err = iokit_mod_send_right( task: from_task, name, delta: -2 ); |
4819 | err = kIOReturnSuccess; |
4820 | } else { |
4821 | IOMachPort::releasePortForObject( obj: map, type: IKOT_IOKIT_OBJECT ); |
4822 | } |
4823 | if (!is_shared_instance_or_from_current_task) { |
4824 | map->release(); |
4825 | } |
4826 | } else { |
4827 | err = kIOReturnBadArgument; |
4828 | } |
4829 | } |
4830 | |
4831 | client->ipcExit(locking: client->defaultLocking ? kIPCLockWrite : kIPCLockNone); |
4832 | |
4833 | return err; |
4834 | } |
4835 | |
4836 | kern_return_t |
4837 | is_io_connect_unmap_memory( |
4838 | io_object_t connect, |
4839 | uint32_t type, |
4840 | task_t task, |
4841 | uint32_t mapAddr ) |
4842 | { |
4843 | IOReturn err; |
4844 | mach_vm_address_t address; |
4845 | |
4846 | address = SCALAR64(mapAddr); |
4847 | |
4848 | err = is_io_connect_unmap_memory_from_task(connection: connect, memory_type: type, from_task: task, address: mapAddr); |
4849 | |
4850 | return err; |
4851 | } |
4852 | |
4853 | |
4854 | /* Routine io_connect_add_client */ |
4855 | kern_return_t |
4856 | is_io_connect_add_client( |
4857 | io_connect_t connection, |
4858 | io_object_t connect_to) |
4859 | { |
4860 | CHECK( IOUserClient, connection, client ); |
4861 | CHECK( IOUserClient, connect_to, to ); |
4862 | |
4863 | IOReturn ret; |
4864 | |
4865 | IOStatisticsClientCall(); |
4866 | |
4867 | client->ipcEnter(locking: client->defaultLocking ? kIPCLockWrite : kIPCLockNone); |
4868 | ret = client->connectClient( to ); |
4869 | client->ipcExit(locking: client->defaultLocking ? kIPCLockWrite : kIPCLockNone); |
4870 | |
4871 | return ret; |
4872 | } |
4873 | |
4874 | |
4875 | /* Routine io_connect_set_properties */ |
4876 | kern_return_t |
4877 | is_io_connect_set_properties( |
4878 | io_connect_t connection, |
4879 | io_buf_ptr_t properties, |
4880 | mach_msg_type_number_t propertiesCnt, |
4881 | kern_return_t * result) |
4882 | { |
4883 | return is_io_registry_entry_set_properties( registry_entry: connection, properties, propertiesCnt, result ); |
4884 | } |
4885 | |
4886 | /* Routine io_user_client_method */ |
4887 | kern_return_t |
4888 | is_io_connect_method_var_output |
4889 | ( |
4890 | io_connect_t connection, |
4891 | uint32_t selector, |
4892 | io_scalar_inband64_t scalar_input, |
4893 | mach_msg_type_number_t scalar_inputCnt, |
4894 | io_struct_inband_t inband_input, |
4895 | mach_msg_type_number_t inband_inputCnt, |
4896 | mach_vm_address_t ool_input, |
4897 | mach_vm_size_t ool_input_size, |
4898 | io_struct_inband_t inband_output, |
4899 | mach_msg_type_number_t *inband_outputCnt, |
4900 | io_scalar_inband64_t scalar_output, |
4901 | mach_msg_type_number_t *scalar_outputCnt, |
4902 | io_buf_ptr_t *var_output, |
4903 | mach_msg_type_number_t *var_outputCnt |
4904 | ) |
4905 | { |
4906 | CHECK( IOUserClient, connection, client ); |
4907 | |
4908 | IOExternalMethodArguments args; |
4909 | IOReturn ret; |
4910 | IOMemoryDescriptor * inputMD = NULL; |
4911 | OSObject * structureVariableOutputData = NULL; |
4912 | |
4913 | bzero(s: &args.__reserved[0], n: sizeof(args.__reserved)); |
4914 | args.__reservedA = 0; |
4915 | args.version = kIOExternalMethodArgumentsCurrentVersion; |
4916 | |
4917 | args.selector = selector; |
4918 | |
4919 | args.asyncWakePort = MACH_PORT_NULL; |
4920 | args.asyncReference = NULL; |
4921 | args.asyncReferenceCount = 0; |
4922 | args.structureVariableOutputData = &structureVariableOutputData; |
4923 | |
4924 | args.scalarInput = scalar_input; |
4925 | args.scalarInputCount = scalar_inputCnt; |
4926 | args.structureInput = inband_input; |
4927 | args.structureInputSize = inband_inputCnt; |
4928 | |
4929 | if (ool_input && (ool_input_size <= sizeof(io_struct_inband_t))) { |
4930 | return kIOReturnIPCError; |
4931 | } |
4932 | |
4933 | if (ool_input) { |
4934 | inputMD = IOMemoryDescriptor::withAddressRange(address: ool_input, length: ool_input_size, |
4935 | options: kIODirectionOut | kIOMemoryMapCopyOnWrite, |
4936 | task: current_task()); |
4937 | } |
4938 | |
4939 | args.structureInputDescriptor = inputMD; |
4940 | |
4941 | args.scalarOutput = scalar_output; |
4942 | args.scalarOutputCount = *scalar_outputCnt; |
4943 | bzero(s: &scalar_output[0], n: *scalar_outputCnt * sizeof(scalar_output[0])); |
4944 | args.structureOutput = inband_output; |
4945 | args.structureOutputSize = *inband_outputCnt; |
4946 | args.structureOutputDescriptor = NULL; |
4947 | args.structureOutputDescriptorSize = 0; |
4948 | |
4949 | IOStatisticsClientCall(); |
4950 | ret = kIOReturnSuccess; |
4951 | |
4952 | io_filter_policy_t filterPolicy = client->filterForTask(task: current_task(), addFilterPolicy: 0); |
4953 | if (filterPolicy && gIOUCFilterCallbacks->io_filter_applier) { |
4954 | ret = gIOUCFilterCallbacks->io_filter_applier(client, filterPolicy, io_filter_type_external_method, selector); |
4955 | } |
4956 | |
4957 | if (kIOReturnSuccess == ret) { |
4958 | ret = client->callExternalMethod(selector, arguments: &args); |
4959 | } |
4960 | |
4961 | *scalar_outputCnt = args.scalarOutputCount; |
4962 | *inband_outputCnt = args.structureOutputSize; |
4963 | |
4964 | if (var_outputCnt && var_output && (kIOReturnSuccess == ret)) { |
4965 | OSSerialize * serialize; |
4966 | OSData * data; |
4967 | unsigned int len; |
4968 | |
4969 | if ((serialize = OSDynamicCast(OSSerialize, structureVariableOutputData))) { |
4970 | len = serialize->getLength(); |
4971 | *var_outputCnt = len; |
4972 | ret = copyoutkdata(data: serialize->text(), len, buf: var_output); |
4973 | } else if ((data = OSDynamicCast(OSData, structureVariableOutputData))) { |
4974 | data->clipForCopyout(); |
4975 | len = data->getLength(); |
4976 | *var_outputCnt = len; |
4977 | ret = copyoutkdata(data: data->getBytesNoCopy(), len, buf: var_output); |
4978 | } else { |
4979 | ret = kIOReturnUnderrun; |
4980 | } |
4981 | } |
4982 | |
4983 | if (inputMD) { |
4984 | inputMD->release(); |
4985 | } |
4986 | if (structureVariableOutputData) { |
4987 | structureVariableOutputData->release(); |
4988 | } |
4989 | |
4990 | return ret; |
4991 | } |
4992 | |
4993 | /* Routine io_user_client_method */ |
4994 | kern_return_t |
4995 | is_io_connect_method |
4996 | ( |
4997 | io_connect_t connection, |
4998 | uint32_t selector, |
4999 | io_scalar_inband64_t scalar_input, |
5000 | mach_msg_type_number_t scalar_inputCnt, |
5001 | io_struct_inband_t inband_input, |
5002 | mach_msg_type_number_t inband_inputCnt, |
5003 | mach_vm_address_t ool_input, |
5004 | mach_vm_size_t ool_input_size, |
5005 | io_struct_inband_t inband_output, |
5006 | mach_msg_type_number_t *inband_outputCnt, |
5007 | io_scalar_inband64_t scalar_output, |
5008 | mach_msg_type_number_t *scalar_outputCnt, |
5009 | mach_vm_address_t ool_output, |
5010 | mach_vm_size_t *ool_output_size |
5011 | ) |
5012 | { |
5013 | CHECK( IOUserClient, connection, client ); |
5014 | |
5015 | IOExternalMethodArguments args; |
5016 | IOReturn ret; |
5017 | IOMemoryDescriptor * inputMD = NULL; |
5018 | IOMemoryDescriptor * outputMD = NULL; |
5019 | |
5020 | bzero(s: &args.__reserved[0], n: sizeof(args.__reserved)); |
5021 | args.__reservedA = 0; |
5022 | args.version = kIOExternalMethodArgumentsCurrentVersion; |
5023 | |
5024 | args.selector = selector; |
5025 | |
5026 | args.asyncWakePort = MACH_PORT_NULL; |
5027 | args.asyncReference = NULL; |
5028 | args.asyncReferenceCount = 0; |
5029 | args.structureVariableOutputData = NULL; |
5030 | |
5031 | args.scalarInput = scalar_input; |
5032 | args.scalarInputCount = scalar_inputCnt; |
5033 | args.structureInput = inband_input; |
5034 | args.structureInputSize = inband_inputCnt; |
5035 | |
5036 | if (ool_input && (ool_input_size <= sizeof(io_struct_inband_t))) { |
5037 | return kIOReturnIPCError; |
5038 | } |
5039 | if (ool_output) { |
5040 | if (*ool_output_size <= sizeof(io_struct_inband_t)) { |
5041 | return kIOReturnIPCError; |
5042 | } |
5043 | if (*ool_output_size > UINT_MAX) { |
5044 | return kIOReturnIPCError; |
5045 | } |
5046 | } |
5047 | |
5048 | if (ool_input) { |
5049 | inputMD = IOMemoryDescriptor::withAddressRange(address: ool_input, length: ool_input_size, |
5050 | options: kIODirectionOut | kIOMemoryMapCopyOnWrite, |
5051 | task: current_task()); |
5052 | } |
5053 | |
5054 | args.structureInputDescriptor = inputMD; |
5055 | |
5056 | args.scalarOutput = scalar_output; |
5057 | args.scalarOutputCount = *scalar_outputCnt; |
5058 | bzero(s: &scalar_output[0], n: *scalar_outputCnt * sizeof(scalar_output[0])); |
5059 | args.structureOutput = inband_output; |
5060 | args.structureOutputSize = *inband_outputCnt; |
5061 | |
5062 | if (ool_output && ool_output_size) { |
5063 | outputMD = IOMemoryDescriptor::withAddressRange(address: ool_output, length: *ool_output_size, |
5064 | options: kIODirectionIn, task: current_task()); |
5065 | } |
5066 | |
5067 | args.structureOutputDescriptor = outputMD; |
5068 | args.structureOutputDescriptorSize = ool_output_size |
5069 | ? ((typeof(args.structureOutputDescriptorSize)) * ool_output_size) |
5070 | : 0; |
5071 | |
5072 | IOStatisticsClientCall(); |
5073 | ret = kIOReturnSuccess; |
5074 | io_filter_policy_t filterPolicy = client->filterForTask(task: current_task(), addFilterPolicy: 0); |
5075 | if (filterPolicy && gIOUCFilterCallbacks->io_filter_applier) { |
5076 | ret = gIOUCFilterCallbacks->io_filter_applier(client, filterPolicy, io_filter_type_external_method, selector); |
5077 | } |
5078 | if (kIOReturnSuccess == ret) { |
5079 | ret = client->callExternalMethod( selector, arguments: &args ); |
5080 | } |
5081 | |
5082 | *scalar_outputCnt = args.scalarOutputCount; |
5083 | *inband_outputCnt = args.structureOutputSize; |
5084 | *ool_output_size = args.structureOutputDescriptorSize; |
5085 | |
5086 | if (inputMD) { |
5087 | inputMD->release(); |
5088 | } |
5089 | if (outputMD) { |
5090 | outputMD->release(); |
5091 | } |
5092 | |
5093 | return ret; |
5094 | } |
5095 | |
5096 | /* Routine io_async_user_client_method */ |
5097 | kern_return_t |
5098 | is_io_connect_async_method |
5099 | ( |
5100 | io_connect_t connection, |
5101 | mach_port_t wake_port, |
5102 | io_async_ref64_t reference, |
5103 | mach_msg_type_number_t referenceCnt, |
5104 | uint32_t selector, |
5105 | io_scalar_inband64_t scalar_input, |
5106 | mach_msg_type_number_t scalar_inputCnt, |
5107 | io_struct_inband_t inband_input, |
5108 | mach_msg_type_number_t inband_inputCnt, |
5109 | mach_vm_address_t ool_input, |
5110 | mach_vm_size_t ool_input_size, |
5111 | io_struct_inband_t inband_output, |
5112 | mach_msg_type_number_t *inband_outputCnt, |
5113 | io_scalar_inband64_t scalar_output, |
5114 | mach_msg_type_number_t *scalar_outputCnt, |
5115 | mach_vm_address_t ool_output, |
5116 | mach_vm_size_t * ool_output_size |
5117 | ) |
5118 | { |
5119 | CHECK( IOUserClient, connection, client ); |
5120 | |
5121 | IOExternalMethodArguments args; |
5122 | IOReturn ret; |
5123 | IOMemoryDescriptor * inputMD = NULL; |
5124 | IOMemoryDescriptor * outputMD = NULL; |
5125 | |
5126 | if (referenceCnt < 1) { |
5127 | return kIOReturnBadArgument; |
5128 | } |
5129 | |
5130 | bzero(s: &args.__reserved[0], n: sizeof(args.__reserved)); |
5131 | args.__reservedA = 0; |
5132 | args.version = kIOExternalMethodArgumentsCurrentVersion; |
5133 | |
5134 | reference[0] = (io_user_reference_t) wake_port; |
5135 | if (vm_map_is_64bit(map: get_task_map(current_task()))) { |
5136 | reference[0] |= kIOUCAsync64Flag; |
5137 | } |
5138 | |
5139 | args.selector = selector; |
5140 | |
5141 | args.asyncWakePort = wake_port; |
5142 | args.asyncReference = reference; |
5143 | args.asyncReferenceCount = referenceCnt; |
5144 | |
5145 | args.structureVariableOutputData = NULL; |
5146 | |
5147 | args.scalarInput = scalar_input; |
5148 | args.scalarInputCount = scalar_inputCnt; |
5149 | args.structureInput = inband_input; |
5150 | args.structureInputSize = inband_inputCnt; |
5151 | |
5152 | if (ool_input && (ool_input_size <= sizeof(io_struct_inband_t))) { |
5153 | return kIOReturnIPCError; |
5154 | } |
5155 | if (ool_output) { |
5156 | if (*ool_output_size <= sizeof(io_struct_inband_t)) { |
5157 | return kIOReturnIPCError; |
5158 | } |
5159 | if (*ool_output_size > UINT_MAX) { |
5160 | return kIOReturnIPCError; |
5161 | } |
5162 | } |
5163 | |
5164 | if (ool_input) { |
5165 | inputMD = IOMemoryDescriptor::withAddressRange(address: ool_input, length: ool_input_size, |
5166 | options: kIODirectionOut | kIOMemoryMapCopyOnWrite, |
5167 | task: current_task()); |
5168 | } |
5169 | |
5170 | args.structureInputDescriptor = inputMD; |
5171 | |
5172 | args.scalarOutput = scalar_output; |
5173 | args.scalarOutputCount = *scalar_outputCnt; |
5174 | bzero(s: &scalar_output[0], n: *scalar_outputCnt * sizeof(scalar_output[0])); |
5175 | args.structureOutput = inband_output; |
5176 | args.structureOutputSize = *inband_outputCnt; |
5177 | |
5178 | if (ool_output) { |
5179 | outputMD = IOMemoryDescriptor::withAddressRange(address: ool_output, length: *ool_output_size, |
5180 | options: kIODirectionIn, task: current_task()); |
5181 | } |
5182 | |
5183 | args.structureOutputDescriptor = outputMD; |
5184 | args.structureOutputDescriptorSize = ((typeof(args.structureOutputDescriptorSize)) * ool_output_size); |
5185 | |
5186 | IOStatisticsClientCall(); |
5187 | ret = kIOReturnSuccess; |
5188 | io_filter_policy_t filterPolicy = client->filterForTask(task: current_task(), addFilterPolicy: 0); |
5189 | if (filterPolicy && gIOUCFilterCallbacks->io_filter_applier) { |
5190 | ret = gIOUCFilterCallbacks->io_filter_applier(client, filterPolicy, io_filter_type_external_async_method, selector); |
5191 | } |
5192 | if (kIOReturnSuccess == ret) { |
5193 | ret = client->callExternalMethod( selector, arguments: &args ); |
5194 | } |
5195 | |
5196 | *scalar_outputCnt = args.scalarOutputCount; |
5197 | *inband_outputCnt = args.structureOutputSize; |
5198 | *ool_output_size = args.structureOutputDescriptorSize; |
5199 | |
5200 | if (inputMD) { |
5201 | inputMD->release(); |
5202 | } |
5203 | if (outputMD) { |
5204 | outputMD->release(); |
5205 | } |
5206 | |
5207 | return ret; |
5208 | } |
5209 | |
5210 | /* Routine io_connect_method_scalarI_scalarO */ |
5211 | kern_return_t |
5212 | is_io_connect_method_scalarI_scalarO( |
5213 | io_object_t connect, |
5214 | uint32_t index, |
5215 | io_scalar_inband_t input, |
5216 | mach_msg_type_number_t inputCount, |
5217 | io_scalar_inband_t output, |
5218 | mach_msg_type_number_t * outputCount ) |
5219 | { |
5220 | IOReturn err; |
5221 | uint32_t i; |
5222 | io_scalar_inband64_t _input; |
5223 | io_scalar_inband64_t _output; |
5224 | |
5225 | mach_msg_type_number_t struct_outputCnt = 0; |
5226 | mach_vm_size_t ool_output_size = 0; |
5227 | |
5228 | bzero(s: &_output[0], n: sizeof(_output)); |
5229 | for (i = 0; i < inputCount; i++) { |
5230 | _input[i] = SCALAR64(input[i]); |
5231 | } |
5232 | |
5233 | err = is_io_connect_method(connection: connect, selector: index, |
5234 | scalar_input: _input, scalar_inputCnt: inputCount, |
5235 | NULL, inband_inputCnt: 0, |
5236 | ool_input: 0, ool_input_size: 0, |
5237 | NULL, inband_outputCnt: &struct_outputCnt, |
5238 | scalar_output: _output, scalar_outputCnt: outputCount, |
5239 | ool_output: 0, ool_output_size: &ool_output_size); |
5240 | |
5241 | for (i = 0; i < *outputCount; i++) { |
5242 | output[i] = SCALAR32(_output[i]); |
5243 | } |
5244 | |
5245 | return err; |
5246 | } |
5247 | |
5248 | kern_return_t |
5249 | shim_io_connect_method_scalarI_scalarO( |
5250 | IOExternalMethod * method, |
5251 | IOService * object, |
5252 | const io_user_scalar_t * input, |
5253 | mach_msg_type_number_t inputCount, |
5254 | io_user_scalar_t * output, |
5255 | mach_msg_type_number_t * outputCount ) |
5256 | { |
5257 | IOMethod func; |
5258 | io_scalar_inband_t _output; |
5259 | IOReturn err; |
5260 | err = kIOReturnBadArgument; |
5261 | |
5262 | bzero(s: &_output[0], n: sizeof(_output)); |
5263 | do { |
5264 | if (inputCount != method->count0) { |
5265 | IOLog(format: "%s:%d %s: IOUserClient inputCount count mismatch 0x%llx 0x%llx\n" , __FUNCTION__, __LINE__, object->getName(), (uint64_t)inputCount, (uint64_t)method->count0); |
5266 | DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)inputCount, uint64_t, (uint64_t)method->count0); |
5267 | continue; |
5268 | } |
5269 | if (*outputCount != method->count1) { |
5270 | IOLog(format: "%s:%d %s: IOUserClient outputCount count mismatch 0x%llx 0x%llx\n" , __FUNCTION__, __LINE__, object->getName(), (uint64_t)*outputCount, (uint64_t)method->count1); |
5271 | DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)*outputCount, uint64_t, (uint64_t)method->count1); |
5272 | continue; |
5273 | } |
5274 | |
5275 | func = method->func; |
5276 | |
5277 | switch (inputCount) { |
5278 | case 6: |
5279 | err = (object->*func)( ARG32(input[0]), ARG32(input[1]), ARG32(input[2]), |
5280 | ARG32(input[3]), ARG32(input[4]), ARG32(input[5])); |
5281 | break; |
5282 | case 5: |
5283 | err = (object->*func)( ARG32(input[0]), ARG32(input[1]), ARG32(input[2]), |
5284 | ARG32(input[3]), ARG32(input[4]), |
5285 | &_output[0] ); |
5286 | break; |
5287 | case 4: |
5288 | err = (object->*func)( ARG32(input[0]), ARG32(input[1]), ARG32(input[2]), |
5289 | ARG32(input[3]), |
5290 | &_output[0], &_output[1] ); |
5291 | break; |
5292 | case 3: |
5293 | err = (object->*func)( ARG32(input[0]), ARG32(input[1]), ARG32(input[2]), |
5294 | &_output[0], &_output[1], &_output[2] ); |
5295 | break; |
5296 | case 2: |
5297 | err = (object->*func)( ARG32(input[0]), ARG32(input[1]), |
5298 | &_output[0], &_output[1], &_output[2], |
5299 | &_output[3] ); |
5300 | break; |
5301 | case 1: |
5302 | err = (object->*func)( ARG32(input[0]), |
5303 | &_output[0], &_output[1], &_output[2], |
5304 | &_output[3], &_output[4] ); |
5305 | break; |
5306 | case 0: |
5307 | err = (object->*func)( &_output[0], &_output[1], &_output[2], |
5308 | &_output[3], &_output[4], &_output[5] ); |
5309 | break; |
5310 | |
5311 | default: |
5312 | IOLog(format: "%s: Bad method table\n" , object->getName()); |
5313 | } |
5314 | }while (false); |
5315 | |
5316 | uint32_t i; |
5317 | for (i = 0; i < *outputCount; i++) { |
5318 | output[i] = SCALAR32(_output[i]); |
5319 | } |
5320 | |
5321 | return err; |
5322 | } |
5323 | |
5324 | /* Routine io_async_method_scalarI_scalarO */ |
5325 | kern_return_t |
5326 | is_io_async_method_scalarI_scalarO( |
5327 | io_object_t connect, |
5328 | mach_port_t wake_port, |
5329 | io_async_ref_t reference, |
5330 | mach_msg_type_number_t referenceCnt, |
5331 | uint32_t index, |
5332 | io_scalar_inband_t input, |
5333 | mach_msg_type_number_t inputCount, |
5334 | io_scalar_inband_t output, |
5335 | mach_msg_type_number_t * outputCount ) |
5336 | { |
5337 | IOReturn err; |
5338 | uint32_t i; |
5339 | io_scalar_inband64_t _input; |
5340 | io_scalar_inband64_t _output; |
5341 | io_async_ref64_t _reference; |
5342 | |
5343 | if (referenceCnt > ASYNC_REF64_COUNT) { |
5344 | return kIOReturnBadArgument; |
5345 | } |
5346 | bzero(s: &_output[0], n: sizeof(_output)); |
5347 | for (i = 0; i < referenceCnt; i++) { |
5348 | _reference[i] = REF64(reference[i]); |
5349 | } |
5350 | bzero(s: &_reference[referenceCnt], n: (ASYNC_REF64_COUNT - referenceCnt) * sizeof(_reference[0])); |
5351 | |
5352 | mach_msg_type_number_t struct_outputCnt = 0; |
5353 | mach_vm_size_t ool_output_size = 0; |
5354 | |
5355 | for (i = 0; i < inputCount; i++) { |
5356 | _input[i] = SCALAR64(input[i]); |
5357 | } |
5358 | |
5359 | err = is_io_connect_async_method(connection: connect, |
5360 | wake_port, reference: _reference, referenceCnt, |
5361 | selector: index, |
5362 | scalar_input: _input, scalar_inputCnt: inputCount, |
5363 | NULL, inband_inputCnt: 0, |
5364 | ool_input: 0, ool_input_size: 0, |
5365 | NULL, inband_outputCnt: &struct_outputCnt, |
5366 | scalar_output: _output, scalar_outputCnt: outputCount, |
5367 | ool_output: 0, ool_output_size: &ool_output_size); |
5368 | |
5369 | for (i = 0; i < *outputCount; i++) { |
5370 | output[i] = SCALAR32(_output[i]); |
5371 | } |
5372 | |
5373 | return err; |
5374 | } |
5375 | /* Routine io_async_method_scalarI_structureO */ |
5376 | kern_return_t |
5377 | is_io_async_method_scalarI_structureO( |
5378 | io_object_t connect, |
5379 | mach_port_t wake_port, |
5380 | io_async_ref_t reference, |
5381 | mach_msg_type_number_t referenceCnt, |
5382 | uint32_t index, |
5383 | io_scalar_inband_t input, |
5384 | mach_msg_type_number_t inputCount, |
5385 | io_struct_inband_t output, |
5386 | mach_msg_type_number_t * outputCount ) |
5387 | { |
5388 | uint32_t i; |
5389 | io_scalar_inband64_t _input; |
5390 | io_async_ref64_t _reference; |
5391 | |
5392 | if (referenceCnt > ASYNC_REF64_COUNT) { |
5393 | return kIOReturnBadArgument; |
5394 | } |
5395 | for (i = 0; i < referenceCnt; i++) { |
5396 | _reference[i] = REF64(reference[i]); |
5397 | } |
5398 | bzero(s: &_reference[referenceCnt], n: (ASYNC_REF64_COUNT - referenceCnt) * sizeof(_reference[0])); |
5399 | |
5400 | mach_msg_type_number_t scalar_outputCnt = 0; |
5401 | mach_vm_size_t ool_output_size = 0; |
5402 | |
5403 | for (i = 0; i < inputCount; i++) { |
5404 | _input[i] = SCALAR64(input[i]); |
5405 | } |
5406 | |
5407 | return is_io_connect_async_method(connection: connect, |
5408 | wake_port, reference: _reference, referenceCnt, |
5409 | selector: index, |
5410 | scalar_input: _input, scalar_inputCnt: inputCount, |
5411 | NULL, inband_inputCnt: 0, |
5412 | ool_input: 0, ool_input_size: 0, |
5413 | inband_output: output, inband_outputCnt: outputCount, |
5414 | NULL, scalar_outputCnt: &scalar_outputCnt, |
5415 | ool_output: 0, ool_output_size: &ool_output_size); |
5416 | } |
5417 | |
5418 | /* Routine io_async_method_scalarI_structureI */ |
5419 | kern_return_t |
5420 | is_io_async_method_scalarI_structureI( |
5421 | io_connect_t connect, |
5422 | mach_port_t wake_port, |
5423 | io_async_ref_t reference, |
5424 | mach_msg_type_number_t referenceCnt, |
5425 | uint32_t index, |
5426 | io_scalar_inband_t input, |
5427 | mach_msg_type_number_t inputCount, |
5428 | io_struct_inband_t inputStruct, |
5429 | mach_msg_type_number_t inputStructCount ) |
5430 | { |
5431 | uint32_t i; |
5432 | io_scalar_inband64_t _input; |
5433 | io_async_ref64_t _reference; |
5434 | |
5435 | if (referenceCnt > ASYNC_REF64_COUNT) { |
5436 | return kIOReturnBadArgument; |
5437 | } |
5438 | for (i = 0; i < referenceCnt; i++) { |
5439 | _reference[i] = REF64(reference[i]); |
5440 | } |
5441 | bzero(s: &_reference[referenceCnt], n: (ASYNC_REF64_COUNT - referenceCnt) * sizeof(_reference[0])); |
5442 | |
5443 | mach_msg_type_number_t scalar_outputCnt = 0; |
5444 | mach_msg_type_number_t inband_outputCnt = 0; |
5445 | mach_vm_size_t ool_output_size = 0; |
5446 | |
5447 | for (i = 0; i < inputCount; i++) { |
5448 | _input[i] = SCALAR64(input[i]); |
5449 | } |
5450 | |
5451 | return is_io_connect_async_method(connection: connect, |
5452 | wake_port, reference: _reference, referenceCnt, |
5453 | selector: index, |
5454 | scalar_input: _input, scalar_inputCnt: inputCount, |
5455 | inband_input: inputStruct, inband_inputCnt: inputStructCount, |
5456 | ool_input: 0, ool_input_size: 0, |
5457 | NULL, inband_outputCnt: &inband_outputCnt, |
5458 | NULL, scalar_outputCnt: &scalar_outputCnt, |
5459 | ool_output: 0, ool_output_size: &ool_output_size); |
5460 | } |
5461 | |
5462 | /* Routine io_async_method_structureI_structureO */ |
5463 | kern_return_t |
5464 | is_io_async_method_structureI_structureO( |
5465 | io_object_t connect, |
5466 | mach_port_t wake_port, |
5467 | io_async_ref_t reference, |
5468 | mach_msg_type_number_t referenceCnt, |
5469 | uint32_t index, |
5470 | io_struct_inband_t input, |
5471 | mach_msg_type_number_t inputCount, |
5472 | io_struct_inband_t output, |
5473 | mach_msg_type_number_t * outputCount ) |
5474 | { |
5475 | uint32_t i; |
5476 | mach_msg_type_number_t scalar_outputCnt = 0; |
5477 | mach_vm_size_t ool_output_size = 0; |
5478 | io_async_ref64_t _reference; |
5479 | |
5480 | if (referenceCnt > ASYNC_REF64_COUNT) { |
5481 | return kIOReturnBadArgument; |
5482 | } |
5483 | for (i = 0; i < referenceCnt; i++) { |
5484 | _reference[i] = REF64(reference[i]); |
5485 | } |
5486 | bzero(s: &_reference[referenceCnt], n: (ASYNC_REF64_COUNT - referenceCnt) * sizeof(_reference[0])); |
5487 | |
5488 | return is_io_connect_async_method(connection: connect, |
5489 | wake_port, reference: _reference, referenceCnt, |
5490 | selector: index, |
5491 | NULL, scalar_inputCnt: 0, |
5492 | inband_input: input, inband_inputCnt: inputCount, |
5493 | ool_input: 0, ool_input_size: 0, |
5494 | inband_output: output, inband_outputCnt: outputCount, |
5495 | NULL, scalar_outputCnt: &scalar_outputCnt, |
5496 | ool_output: 0, ool_output_size: &ool_output_size); |
5497 | } |
5498 | |
5499 | |
5500 | kern_return_t |
5501 | shim_io_async_method_scalarI_scalarO( |
5502 | IOExternalAsyncMethod * method, |
5503 | IOService * object, |
5504 | mach_port_t asyncWakePort, |
5505 | io_user_reference_t * asyncReference, |
5506 | uint32_t asyncReferenceCount, |
5507 | const io_user_scalar_t * input, |
5508 | mach_msg_type_number_t inputCount, |
5509 | io_user_scalar_t * output, |
5510 | mach_msg_type_number_t * outputCount ) |
5511 | { |
5512 | IOAsyncMethod func; |
5513 | uint32_t i; |
5514 | io_scalar_inband_t _output; |
5515 | IOReturn err; |
5516 | io_async_ref_t reference; |
5517 | |
5518 | bzero(s: &_output[0], n: sizeof(_output)); |
5519 | for (i = 0; i < asyncReferenceCount; i++) { |
5520 | reference[i] = REF32(asyncReference[i]); |
5521 | } |
5522 | |
5523 | err = kIOReturnBadArgument; |
5524 | |
5525 | do { |
5526 | if (inputCount != method->count0) { |
5527 | IOLog(format: "%s:%d %s: IOUserClient inputCount count mismatch 0x%llx 0x%llx\n" , __FUNCTION__, __LINE__, object->getName(), (uint64_t)inputCount, (uint64_t)method->count0); |
5528 | DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)inputCount, uint64_t, (uint64_t)method->count0); |
5529 | continue; |
5530 | } |
5531 | if (*outputCount != method->count1) { |
5532 | IOLog(format: "%s:%d %s: IOUserClient outputCount count mismatch 0x%llx 0x%llx\n" , __FUNCTION__, __LINE__, object->getName(), (uint64_t)*outputCount, (uint64_t)method->count1); |
5533 | DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)*outputCount, uint64_t, (uint64_t)method->count1); |
5534 | continue; |
5535 | } |
5536 | |
5537 | func = method->func; |
5538 | |
5539 | switch (inputCount) { |
5540 | case 6: |
5541 | err = (object->*func)( reference, |
5542 | ARG32(input[0]), ARG32(input[1]), ARG32(input[2]), |
5543 | ARG32(input[3]), ARG32(input[4]), ARG32(input[5])); |
5544 | break; |
5545 | case 5: |
5546 | err = (object->*func)( reference, |
5547 | ARG32(input[0]), ARG32(input[1]), ARG32(input[2]), |
5548 | ARG32(input[3]), ARG32(input[4]), |
5549 | &_output[0] ); |
5550 | break; |
5551 | case 4: |
5552 | err = (object->*func)( reference, |
5553 | ARG32(input[0]), ARG32(input[1]), ARG32(input[2]), |
5554 | ARG32(input[3]), |
5555 | &_output[0], &_output[1] ); |
5556 | break; |
5557 | case 3: |
5558 | err = (object->*func)( reference, |
5559 | ARG32(input[0]), ARG32(input[1]), ARG32(input[2]), |
5560 | &_output[0], &_output[1], &_output[2] ); |
5561 | break; |
5562 | case 2: |
5563 | err = (object->*func)( reference, |
5564 | ARG32(input[0]), ARG32(input[1]), |
5565 | &_output[0], &_output[1], &_output[2], |
5566 | &_output[3] ); |
5567 | break; |
5568 | case 1: |
5569 | err = (object->*func)( reference, |
5570 | ARG32(input[0]), |
5571 | &_output[0], &_output[1], &_output[2], |
5572 | &_output[3], &_output[4] ); |
5573 | break; |
5574 | case 0: |
5575 | err = (object->*func)( reference, |
5576 | &_output[0], &_output[1], &_output[2], |
5577 | &_output[3], &_output[4], &_output[5] ); |
5578 | break; |
5579 | |
5580 | default: |
5581 | IOLog(format: "%s: Bad method table\n" , object->getName()); |
5582 | } |
5583 | }while (false); |
5584 | |
5585 | for (i = 0; i < *outputCount; i++) { |
5586 | output[i] = SCALAR32(_output[i]); |
5587 | } |
5588 | |
5589 | return err; |
5590 | } |
5591 | |
5592 | |
5593 | /* Routine io_connect_method_scalarI_structureO */ |
5594 | kern_return_t |
5595 | is_io_connect_method_scalarI_structureO( |
5596 | io_object_t connect, |
5597 | uint32_t index, |
5598 | io_scalar_inband_t input, |
5599 | mach_msg_type_number_t inputCount, |
5600 | io_struct_inband_t output, |
5601 | mach_msg_type_number_t * outputCount ) |
5602 | { |
5603 | uint32_t i; |
5604 | io_scalar_inband64_t _input; |
5605 | |
5606 | mach_msg_type_number_t scalar_outputCnt = 0; |
5607 | mach_vm_size_t ool_output_size = 0; |
5608 | |
5609 | for (i = 0; i < inputCount; i++) { |
5610 | _input[i] = SCALAR64(input[i]); |
5611 | } |
5612 | |
5613 | return is_io_connect_method(connection: connect, selector: index, |
5614 | scalar_input: _input, scalar_inputCnt: inputCount, |
5615 | NULL, inband_inputCnt: 0, |
5616 | ool_input: 0, ool_input_size: 0, |
5617 | inband_output: output, inband_outputCnt: outputCount, |
5618 | NULL, scalar_outputCnt: &scalar_outputCnt, |
5619 | ool_output: 0, ool_output_size: &ool_output_size); |
5620 | } |
5621 | |
5622 | kern_return_t |
5623 | shim_io_connect_method_scalarI_structureO( |
5624 | |
5625 | IOExternalMethod * method, |
5626 | IOService * object, |
5627 | const io_user_scalar_t * input, |
5628 | mach_msg_type_number_t inputCount, |
5629 | io_struct_inband_t output, |
5630 | IOByteCount * outputCount ) |
5631 | { |
5632 | IOMethod func; |
5633 | IOReturn err; |
5634 | |
5635 | err = kIOReturnBadArgument; |
5636 | |
5637 | do { |
5638 | if (inputCount != method->count0) { |
5639 | IOLog(format: "%s:%d %s: IOUserClient inputCount count mismatch 0x%llx 0x%llx\n" , __FUNCTION__, __LINE__, object->getName(), (uint64_t)inputCount, (uint64_t)method->count0); |
5640 | DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)inputCount, uint64_t, (uint64_t)method->count0); |
5641 | continue; |
5642 | } |
5643 | if ((kIOUCVariableStructureSize != method->count1) |
5644 | && (*outputCount != method->count1)) { |
5645 | IOLog(format: "%s:%d %s: IOUserClient outputCount count mismatch 0x%llx 0x%llx 0x%llx\n" , __FUNCTION__, __LINE__, object->getName(), (uint64_t)*outputCount, (uint64_t)method->count1, (uint64_t)kIOUCVariableStructureSize); |
5646 | DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)*outputCount, uint64_t, (uint64_t)method->count1); |
5647 | continue; |
5648 | } |
5649 | |
5650 | func = method->func; |
5651 | |
5652 | switch (inputCount) { |
5653 | case 5: |
5654 | err = (object->*func)( ARG32(input[0]), ARG32(input[1]), ARG32(input[2]), |
5655 | ARG32(input[3]), ARG32(input[4]), |
5656 | output ); |
5657 | break; |
5658 | case 4: |
5659 | err = (object->*func)( ARG32(input[0]), ARG32(input[1]), ARG32(input[2]), |
5660 | ARG32(input[3]), |
5661 | output, (void *)outputCount ); |
5662 | break; |
5663 | case 3: |
5664 | err = (object->*func)( ARG32(input[0]), ARG32(input[1]), ARG32(input[2]), |
5665 | output, (void *)outputCount, NULL ); |
5666 | break; |
5667 | case 2: |
5668 | err = (object->*func)( ARG32(input[0]), ARG32(input[1]), |
5669 | output, (void *)outputCount, NULL, NULL ); |
5670 | break; |
5671 | case 1: |
5672 | err = (object->*func)( ARG32(input[0]), |
5673 | output, (void *)outputCount, NULL, NULL, NULL ); |
5674 | break; |
5675 | case 0: |
5676 | err = (object->*func)( output, (void *)outputCount, NULL, NULL, NULL, NULL ); |
5677 | break; |
5678 | |
5679 | default: |
5680 | IOLog(format: "%s: Bad method table\n" , object->getName()); |
5681 | } |
5682 | }while (false); |
5683 | |
5684 | return err; |
5685 | } |
5686 | |
5687 | |
5688 | kern_return_t |
5689 | shim_io_async_method_scalarI_structureO( |
5690 | IOExternalAsyncMethod * method, |
5691 | IOService * object, |
5692 | mach_port_t asyncWakePort, |
5693 | io_user_reference_t * asyncReference, |
5694 | uint32_t asyncReferenceCount, |
5695 | const io_user_scalar_t * input, |
5696 | mach_msg_type_number_t inputCount, |
5697 | io_struct_inband_t output, |
5698 | mach_msg_type_number_t * outputCount ) |
5699 | { |
5700 | IOAsyncMethod func; |
5701 | uint32_t i; |
5702 | IOReturn err; |
5703 | io_async_ref_t reference; |
5704 | |
5705 | for (i = 0; i < asyncReferenceCount; i++) { |
5706 | reference[i] = REF32(asyncReference[i]); |
5707 | } |
5708 | |
5709 | err = kIOReturnBadArgument; |
5710 | do { |
5711 | if (inputCount != method->count0) { |
5712 | IOLog(format: "%s:%d %s: IOUserClient inputCount count mismatch 0x%llx 0x%llx\n" , __FUNCTION__, __LINE__, object->getName(), (uint64_t)inputCount, (uint64_t)method->count0); |
5713 | DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)inputCount, uint64_t, (uint64_t)method->count0); |
5714 | continue; |
5715 | } |
5716 | if ((kIOUCVariableStructureSize != method->count1) |
5717 | && (*outputCount != method->count1)) { |
5718 | IOLog(format: "%s:%d %s: IOUserClient outputCount count mismatch 0x%llx 0x%llx 0x%llx\n" , __FUNCTION__, __LINE__, object->getName(), (uint64_t)*outputCount, (uint64_t)method->count1, (uint64_t)kIOUCVariableStructureSize); |
5719 | DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)*outputCount, uint64_t, (uint64_t)method->count1); |
5720 | continue; |
5721 | } |
5722 | |
5723 | func = method->func; |
5724 | |
5725 | switch (inputCount) { |
5726 | case 5: |
5727 | err = (object->*func)( reference, |
5728 | ARG32(input[0]), ARG32(input[1]), ARG32(input[2]), |
5729 | ARG32(input[3]), ARG32(input[4]), |
5730 | output ); |
5731 | break; |
5732 | case 4: |
5733 | err = (object->*func)( reference, |
5734 | ARG32(input[0]), ARG32(input[1]), ARG32(input[2]), |
5735 | ARG32(input[3]), |
5736 | output, (void *)outputCount ); |
5737 | break; |
5738 | case 3: |
5739 | err = (object->*func)( reference, |
5740 | ARG32(input[0]), ARG32(input[1]), ARG32(input[2]), |
5741 | output, (void *)outputCount, NULL ); |
5742 | break; |
5743 | case 2: |
5744 | err = (object->*func)( reference, |
5745 | ARG32(input[0]), ARG32(input[1]), |
5746 | output, (void *)outputCount, NULL, NULL ); |
5747 | break; |
5748 | case 1: |
5749 | err = (object->*func)( reference, |
5750 | ARG32(input[0]), |
5751 | output, (void *)outputCount, NULL, NULL, NULL ); |
5752 | break; |
5753 | case 0: |
5754 | err = (object->*func)( reference, |
5755 | output, (void *)outputCount, NULL, NULL, NULL, NULL ); |
5756 | break; |
5757 | |
5758 | default: |
5759 | IOLog(format: "%s: Bad method table\n" , object->getName()); |
5760 | } |
5761 | }while (false); |
5762 | |
5763 | return err; |
5764 | } |
5765 | |
5766 | /* Routine io_connect_method_scalarI_structureI */ |
5767 | kern_return_t |
5768 | is_io_connect_method_scalarI_structureI( |
5769 | io_connect_t connect, |
5770 | uint32_t index, |
5771 | io_scalar_inband_t input, |
5772 | mach_msg_type_number_t inputCount, |
5773 | io_struct_inband_t inputStruct, |
5774 | mach_msg_type_number_t inputStructCount ) |
5775 | { |
5776 | uint32_t i; |
5777 | io_scalar_inband64_t _input; |
5778 | |
5779 | mach_msg_type_number_t scalar_outputCnt = 0; |
5780 | mach_msg_type_number_t inband_outputCnt = 0; |
5781 | mach_vm_size_t ool_output_size = 0; |
5782 | |
5783 | for (i = 0; i < inputCount; i++) { |
5784 | _input[i] = SCALAR64(input[i]); |
5785 | } |
5786 | |
5787 | return is_io_connect_method(connection: connect, selector: index, |
5788 | scalar_input: _input, scalar_inputCnt: inputCount, |
5789 | inband_input: inputStruct, inband_inputCnt: inputStructCount, |
5790 | ool_input: 0, ool_input_size: 0, |
5791 | NULL, inband_outputCnt: &inband_outputCnt, |
5792 | NULL, scalar_outputCnt: &scalar_outputCnt, |
5793 | ool_output: 0, ool_output_size: &ool_output_size); |
5794 | } |
5795 | |
5796 | kern_return_t |
5797 | shim_io_connect_method_scalarI_structureI( |
5798 | IOExternalMethod * method, |
5799 | IOService * object, |
5800 | const io_user_scalar_t * input, |
5801 | mach_msg_type_number_t inputCount, |
5802 | io_struct_inband_t inputStruct, |
5803 | mach_msg_type_number_t inputStructCount ) |
5804 | { |
5805 | IOMethod func; |
5806 | IOReturn err = kIOReturnBadArgument; |
5807 | |
5808 | do{ |
5809 | if (inputCount != method->count0) { |
5810 | IOLog(format: "%s:%d %s: IOUserClient inputCount count mismatch 0x%llx 0x%llx\n" , __FUNCTION__, __LINE__, object->getName(), (uint64_t)inputCount, (uint64_t)method->count0); |
5811 | DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)inputCount, uint64_t, (uint64_t)method->count0); |
5812 | continue; |
5813 | } |
5814 | if ((kIOUCVariableStructureSize != method->count1) |
5815 | && (inputStructCount != method->count1)) { |
5816 | IOLog(format: "%s:%d %s: IOUserClient outputCount count mismatch 0x%llx 0x%llx 0x%llx\n" , __FUNCTION__, __LINE__, object->getName(), (uint64_t)inputStructCount, (uint64_t)method->count1, (uint64_t)kIOUCVariableStructureSize); |
5817 | DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)inputStructCount, uint64_t, (uint64_t)method->count1); |
5818 | continue; |
5819 | } |
5820 | |
5821 | func = method->func; |
5822 | |
5823 | switch (inputCount) { |
5824 | case 5: |
5825 | err = (object->*func)( ARG32(input[0]), ARG32(input[1]), ARG32(input[2]), |
5826 | ARG32(input[3]), ARG32(input[4]), |
5827 | inputStruct ); |
5828 | break; |
5829 | case 4: |
5830 | err = (object->*func)( ARG32(input[0]), ARG32(input[1]), (void *) input[2], |
5831 | ARG32(input[3]), |
5832 | inputStruct, (void *)(uintptr_t)inputStructCount ); |
5833 | break; |
5834 | case 3: |
5835 | err = (object->*func)( ARG32(input[0]), ARG32(input[1]), ARG32(input[2]), |
5836 | inputStruct, (void *)(uintptr_t)inputStructCount, |
5837 | NULL ); |
5838 | break; |
5839 | case 2: |
5840 | err = (object->*func)( ARG32(input[0]), ARG32(input[1]), |
5841 | inputStruct, (void *)(uintptr_t)inputStructCount, |
5842 | NULL, NULL ); |
5843 | break; |
5844 | case 1: |
5845 | err = (object->*func)( ARG32(input[0]), |
5846 | inputStruct, (void *)(uintptr_t)inputStructCount, |
5847 | NULL, NULL, NULL ); |
5848 | break; |
5849 | case 0: |
5850 | err = (object->*func)( inputStruct, (void *)(uintptr_t)inputStructCount, |
5851 | NULL, NULL, NULL, NULL ); |
5852 | break; |
5853 | |
5854 | default: |
5855 | IOLog(format: "%s: Bad method table\n" , object->getName()); |
5856 | } |
5857 | }while (false); |
5858 | |
5859 | return err; |
5860 | } |
5861 | |
5862 | kern_return_t |
5863 | shim_io_async_method_scalarI_structureI( |
5864 | IOExternalAsyncMethod * method, |
5865 | IOService * object, |
5866 | mach_port_t asyncWakePort, |
5867 | io_user_reference_t * asyncReference, |
5868 | uint32_t asyncReferenceCount, |
5869 | const io_user_scalar_t * input, |
5870 | mach_msg_type_number_t inputCount, |
5871 | io_struct_inband_t inputStruct, |
5872 | mach_msg_type_number_t inputStructCount ) |
5873 | { |
5874 | IOAsyncMethod func; |
5875 | uint32_t i; |
5876 | IOReturn err = kIOReturnBadArgument; |
5877 | io_async_ref_t reference; |
5878 | |
5879 | for (i = 0; i < asyncReferenceCount; i++) { |
5880 | reference[i] = REF32(asyncReference[i]); |
5881 | } |
5882 | |
5883 | do{ |
5884 | if (inputCount != method->count0) { |
5885 | IOLog(format: "%s:%d %s: IOUserClient inputCount count mismatch 0x%llx 0x%llx\n" , __FUNCTION__, __LINE__, object->getName(), (uint64_t)inputCount, (uint64_t)method->count0); |
5886 | DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)inputCount, uint64_t, (uint64_t)method->count0); |
5887 | continue; |
5888 | } |
5889 | if ((kIOUCVariableStructureSize != method->count1) |
5890 | && (inputStructCount != method->count1)) { |
5891 | IOLog(format: "%s:%d %s: IOUserClient outputCount count mismatch 0x%llx 0x%llx 0x%llx\n" , __FUNCTION__, __LINE__, object->getName(), (uint64_t)inputStructCount, (uint64_t)method->count1, (uint64_t)kIOUCVariableStructureSize); |
5892 | DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)inputStructCount, uint64_t, (uint64_t)method->count1); |
5893 | continue; |
5894 | } |
5895 | |
5896 | func = method->func; |
5897 | |
5898 | switch (inputCount) { |
5899 | case 5: |
5900 | err = (object->*func)( reference, |
5901 | ARG32(input[0]), ARG32(input[1]), ARG32(input[2]), |
5902 | ARG32(input[3]), ARG32(input[4]), |
5903 | inputStruct ); |
5904 | break; |
5905 | case 4: |
5906 | err = (object->*func)( reference, |
5907 | ARG32(input[0]), ARG32(input[1]), ARG32(input[2]), |
5908 | ARG32(input[3]), |
5909 | inputStruct, (void *)(uintptr_t)inputStructCount ); |
5910 | break; |
5911 | case 3: |
5912 | err = (object->*func)( reference, |
5913 | ARG32(input[0]), ARG32(input[1]), ARG32(input[2]), |
5914 | inputStruct, (void *)(uintptr_t)inputStructCount, |
5915 | NULL ); |
5916 | break; |
5917 | case 2: |
5918 | err = (object->*func)( reference, |
5919 | ARG32(input[0]), ARG32(input[1]), |
5920 | inputStruct, (void *)(uintptr_t)inputStructCount, |
5921 | NULL, NULL ); |
5922 | break; |
5923 | case 1: |
5924 | err = (object->*func)( reference, |
5925 | ARG32(input[0]), |
5926 | inputStruct, (void *)(uintptr_t)inputStructCount, |
5927 | NULL, NULL, NULL ); |
5928 | break; |
5929 | case 0: |
5930 | err = (object->*func)( reference, |
5931 | inputStruct, (void *)(uintptr_t)inputStructCount, |
5932 | NULL, NULL, NULL, NULL ); |
5933 | break; |
5934 | |
5935 | default: |
5936 | IOLog(format: "%s: Bad method table\n" , object->getName()); |
5937 | } |
5938 | }while (false); |
5939 | |
5940 | return err; |
5941 | } |
5942 | |
5943 | /* Routine io_connect_method_structureI_structureO */ |
5944 | kern_return_t |
5945 | is_io_connect_method_structureI_structureO( |
5946 | io_object_t connect, |
5947 | uint32_t index, |
5948 | io_struct_inband_t input, |
5949 | mach_msg_type_number_t inputCount, |
5950 | io_struct_inband_t output, |
5951 | mach_msg_type_number_t * outputCount ) |
5952 | { |
5953 | mach_msg_type_number_t scalar_outputCnt = 0; |
5954 | mach_vm_size_t ool_output_size = 0; |
5955 | |
5956 | return is_io_connect_method(connection: connect, selector: index, |
5957 | NULL, scalar_inputCnt: 0, |
5958 | inband_input: input, inband_inputCnt: inputCount, |
5959 | ool_input: 0, ool_input_size: 0, |
5960 | inband_output: output, inband_outputCnt: outputCount, |
5961 | NULL, scalar_outputCnt: &scalar_outputCnt, |
5962 | ool_output: 0, ool_output_size: &ool_output_size); |
5963 | } |
5964 | |
5965 | kern_return_t |
5966 | shim_io_connect_method_structureI_structureO( |
5967 | IOExternalMethod * method, |
5968 | IOService * object, |
5969 | io_struct_inband_t input, |
5970 | mach_msg_type_number_t inputCount, |
5971 | io_struct_inband_t output, |
5972 | IOByteCount * outputCount ) |
5973 | { |
5974 | IOMethod func; |
5975 | IOReturn err = kIOReturnBadArgument; |
5976 | |
5977 | do{ |
5978 | if ((kIOUCVariableStructureSize != method->count0) |
5979 | && (inputCount != method->count0)) { |
5980 | IOLog(format: "%s:%d %s: IOUserClient inputCount count mismatch 0x%llx 0x%llx 0x%llx\n" , __FUNCTION__, __LINE__, object->getName(), (uint64_t)inputCount, (uint64_t)method->count0, (uint64_t)kIOUCVariableStructureSize); |
5981 | DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)inputCount, uint64_t, (uint64_t)method->count0); |
5982 | continue; |
5983 | } |
5984 | if ((kIOUCVariableStructureSize != method->count1) |
5985 | && (*outputCount != method->count1)) { |
5986 | IOLog(format: "%s:%d %s: IOUserClient outputCount count mismatch 0x%llx 0x%llx 0x%llx\n" , __FUNCTION__, __LINE__, object->getName(), (uint64_t)*outputCount, (uint64_t)method->count1, (uint64_t)kIOUCVariableStructureSize); |
5987 | DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)*outputCount, uint64_t, (uint64_t)method->count1); |
5988 | continue; |
5989 | } |
5990 | |
5991 | func = method->func; |
5992 | |
5993 | if (method->count1) { |
5994 | if (method->count0) { |
5995 | err = (object->*func)( input, output, |
5996 | (void *)(uintptr_t)inputCount, outputCount, NULL, NULL ); |
5997 | } else { |
5998 | err = (object->*func)( output, outputCount, NULL, NULL, NULL, NULL ); |
5999 | } |
6000 | } else { |
6001 | err = (object->*func)( input, (void *)(uintptr_t)inputCount, NULL, NULL, NULL, NULL ); |
6002 | } |
6003 | }while (false); |
6004 | |
6005 | |
6006 | return err; |
6007 | } |
6008 | |
6009 | kern_return_t |
6010 | shim_io_async_method_structureI_structureO( |
6011 | IOExternalAsyncMethod * method, |
6012 | IOService * object, |
6013 | mach_port_t asyncWakePort, |
6014 | io_user_reference_t * asyncReference, |
6015 | uint32_t asyncReferenceCount, |
6016 | io_struct_inband_t input, |
6017 | mach_msg_type_number_t inputCount, |
6018 | io_struct_inband_t output, |
6019 | mach_msg_type_number_t * outputCount ) |
6020 | { |
6021 | IOAsyncMethod func; |
6022 | uint32_t i; |
6023 | IOReturn err; |
6024 | io_async_ref_t reference; |
6025 | |
6026 | for (i = 0; i < asyncReferenceCount; i++) { |
6027 | reference[i] = REF32(asyncReference[i]); |
6028 | } |
6029 | |
6030 | err = kIOReturnBadArgument; |
6031 | do{ |
6032 | if ((kIOUCVariableStructureSize != method->count0) |
6033 | && (inputCount != method->count0)) { |
6034 | IOLog(format: "%s:%d %s: IOUserClient inputCount count mismatch 0x%llx 0x%llx 0x%llx\n" , __FUNCTION__, __LINE__, object->getName(), (uint64_t)inputCount, (uint64_t)method->count0, (uint64_t)kIOUCVariableStructureSize); |
6035 | DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)inputCount, uint64_t, (uint64_t)method->count0); |
6036 | continue; |
6037 | } |
6038 | if ((kIOUCVariableStructureSize != method->count1) |
6039 | && (*outputCount != method->count1)) { |
6040 | IOLog(format: "%s:%d %s: IOUserClient outputCount count mismatch 0x%llx 0x%llx 0x%llx\n" , __FUNCTION__, __LINE__, object->getName(), (uint64_t)*outputCount, (uint64_t)method->count1, (uint64_t)kIOUCVariableStructureSize); |
6041 | DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)*outputCount, uint64_t, (uint64_t)method->count1); |
6042 | continue; |
6043 | } |
6044 | |
6045 | func = method->func; |
6046 | |
6047 | if (method->count1) { |
6048 | if (method->count0) { |
6049 | err = (object->*func)( reference, |
6050 | input, output, |
6051 | (void *)(uintptr_t)inputCount, outputCount, NULL, NULL ); |
6052 | } else { |
6053 | err = (object->*func)( reference, |
6054 | output, outputCount, NULL, NULL, NULL, NULL ); |
6055 | } |
6056 | } else { |
6057 | err = (object->*func)( reference, |
6058 | input, (void *)(uintptr_t)inputCount, NULL, NULL, NULL, NULL ); |
6059 | } |
6060 | }while (false); |
6061 | |
6062 | return err; |
6063 | } |
6064 | |
6065 | /* Routine io_catalog_send_data */ |
6066 | kern_return_t |
6067 | is_io_catalog_send_data( |
6068 | mach_port_t main_port, |
6069 | uint32_t flag, |
6070 | io_buf_ptr_t inData, |
6071 | mach_msg_type_number_t inDataCount, |
6072 | kern_return_t * result) |
6073 | { |
6074 | // Allow sending catalog data if there is no kextd and the kernel is DEVELOPMENT || DEBUG |
6075 | #if NO_KEXTD && !(DEVELOPMENT || DEBUG) |
6076 | return kIOReturnNotPrivileged; |
6077 | #else /* NO_KEXTD && !(DEVELOPMENT || DEBUG) */ |
6078 | OSObject * obj = NULL; |
6079 | vm_offset_t data; |
6080 | kern_return_t kr = kIOReturnError; |
6081 | |
6082 | //printf("io_catalog_send_data called. flag: %d\n", flag); |
6083 | |
6084 | if (main_port != main_device_port) { |
6085 | return kIOReturnNotPrivileged; |
6086 | } |
6087 | |
6088 | if ((flag != kIOCatalogRemoveKernelLinker__Removed && |
6089 | flag != kIOCatalogKextdActive && |
6090 | flag != kIOCatalogKextdFinishedLaunching) && |
6091 | (!inData || !inDataCount)) { |
6092 | return kIOReturnBadArgument; |
6093 | } |
6094 | |
6095 | if (!IOCurrentTaskHasEntitlement(kIOCatalogManagementEntitlement)) { |
6096 | OSString * taskName = IOCopyLogNameForPID(pid: proc_selfpid()); |
6097 | IOLog(format: "IOCatalogueSendData(%s): Not entitled\n" , taskName ? taskName->getCStringNoCopy() : "" ); |
6098 | OSSafeReleaseNULL(taskName); |
6099 | // For now, fake success to not break applications relying on this function succeeding. |
6100 | // See <rdar://problem/32554970> for more details. |
6101 | return kIOReturnSuccess; |
6102 | } |
6103 | |
6104 | if (inData) { |
6105 | vm_map_offset_t map_data; |
6106 | |
6107 | if (inDataCount > sizeof(io_struct_inband_t) * 1024) { |
6108 | return kIOReturnMessageTooLarge; |
6109 | } |
6110 | |
6111 | kr = vm_map_copyout( dst_map: kernel_map, dst_addr: &map_data, copy: (vm_map_copy_t)inData); |
6112 | data = CAST_DOWN(vm_offset_t, map_data); |
6113 | |
6114 | if (kr != KERN_SUCCESS) { |
6115 | return kr; |
6116 | } |
6117 | |
6118 | // must return success after vm_map_copyout() succeeds |
6119 | |
6120 | if (inDataCount) { |
6121 | obj = (OSObject *)OSUnserializeXML(buffer: (const char *)data, bufferSize: inDataCount); |
6122 | vm_deallocate( target_task: kernel_map, address: data, size: inDataCount ); |
6123 | if (!obj) { |
6124 | *result = kIOReturnNoMemory; |
6125 | return KERN_SUCCESS; |
6126 | } |
6127 | } |
6128 | } |
6129 | |
6130 | switch (flag) { |
6131 | case kIOCatalogResetDrivers: |
6132 | case kIOCatalogResetDriversNoMatch: { |
6133 | OSArray * array; |
6134 | |
6135 | array = OSDynamicCast(OSArray, obj); |
6136 | if (array) { |
6137 | if (!gIOCatalogue->resetAndAddDrivers(drivers: array, |
6138 | doNubMatching: flag == kIOCatalogResetDrivers)) { |
6139 | kr = kIOReturnError; |
6140 | } |
6141 | } else { |
6142 | kr = kIOReturnBadArgument; |
6143 | } |
6144 | } |
6145 | break; |
6146 | |
6147 | case kIOCatalogAddDrivers: |
6148 | case kIOCatalogAddDriversNoMatch: { |
6149 | OSArray * array; |
6150 | |
6151 | array = OSDynamicCast(OSArray, obj); |
6152 | if (array) { |
6153 | if (!gIOCatalogue->addDrivers( array, |
6154 | doNubMatching: flag == kIOCatalogAddDrivers)) { |
6155 | kr = kIOReturnError; |
6156 | } |
6157 | } else { |
6158 | kr = kIOReturnBadArgument; |
6159 | } |
6160 | } |
6161 | break; |
6162 | |
6163 | case kIOCatalogRemoveDrivers: |
6164 | case kIOCatalogRemoveDriversNoMatch: { |
6165 | OSDictionary * dict; |
6166 | |
6167 | dict = OSDynamicCast(OSDictionary, obj); |
6168 | if (dict) { |
6169 | if (!gIOCatalogue->removeDrivers( matching: dict, |
6170 | doNubMatching: flag == kIOCatalogRemoveDrivers )) { |
6171 | kr = kIOReturnError; |
6172 | } |
6173 | } else { |
6174 | kr = kIOReturnBadArgument; |
6175 | } |
6176 | } |
6177 | break; |
6178 | |
6179 | case kIOCatalogStartMatching__Removed: |
6180 | case kIOCatalogRemoveKernelLinker__Removed: |
6181 | case kIOCatalogKextdActive: |
6182 | case kIOCatalogKextdFinishedLaunching: |
6183 | kr = KERN_NOT_SUPPORTED; |
6184 | break; |
6185 | |
6186 | default: |
6187 | kr = kIOReturnBadArgument; |
6188 | break; |
6189 | } |
6190 | |
6191 | if (obj) { |
6192 | obj->release(); |
6193 | } |
6194 | |
6195 | *result = kr; |
6196 | return KERN_SUCCESS; |
6197 | #endif /* NO_KEXTD && !(DEVELOPMENT || DEBUG) */ |
6198 | } |
6199 | |
6200 | /* Routine io_catalog_terminate */ |
6201 | kern_return_t |
6202 | is_io_catalog_terminate( |
6203 | mach_port_t main_port, |
6204 | uint32_t flag, |
6205 | io_name_t name ) |
6206 | { |
6207 | kern_return_t kr; |
6208 | |
6209 | if (main_port != main_device_port) { |
6210 | return kIOReturnNotPrivileged; |
6211 | } |
6212 | |
6213 | kr = IOUserClient::clientHasPrivilege(securityToken: (void *) current_task(), |
6214 | kIOClientPrivilegeAdministrator ); |
6215 | if (kIOReturnSuccess != kr) { |
6216 | return kr; |
6217 | } |
6218 | |
6219 | switch (flag) { |
6220 | #if !defined(SECURE_KERNEL) |
6221 | case kIOCatalogServiceTerminate: |
6222 | kr = gIOCatalogue->terminateDrivers(NULL, className: name, asynchronous: false); |
6223 | break; |
6224 | |
6225 | case kIOCatalogModuleUnload: |
6226 | case kIOCatalogModuleTerminate: |
6227 | kr = gIOCatalogue->terminateDriversForModule(moduleName: name, |
6228 | unload: flag == kIOCatalogModuleUnload); |
6229 | break; |
6230 | #endif |
6231 | |
6232 | default: |
6233 | kr = kIOReturnBadArgument; |
6234 | break; |
6235 | } |
6236 | |
6237 | return kr; |
6238 | } |
6239 | |
6240 | /* Routine io_catalog_get_data */ |
6241 | kern_return_t |
6242 | is_io_catalog_get_data( |
6243 | mach_port_t main_port, |
6244 | uint32_t flag, |
6245 | io_buf_ptr_t *outData, |
6246 | mach_msg_type_number_t *outDataCount) |
6247 | { |
6248 | kern_return_t kr = kIOReturnSuccess; |
6249 | OSSerialize * s; |
6250 | |
6251 | if (main_port != main_device_port) { |
6252 | return kIOReturnNotPrivileged; |
6253 | } |
6254 | |
6255 | //printf("io_catalog_get_data called. flag: %d\n", flag); |
6256 | |
6257 | s = OSSerialize::withCapacity(capacity: 4096); |
6258 | if (!s) { |
6259 | return kIOReturnNoMemory; |
6260 | } |
6261 | |
6262 | kr = gIOCatalogue->serializeData(kind: flag, s); |
6263 | |
6264 | if (kr == kIOReturnSuccess) { |
6265 | mach_vm_address_t data; |
6266 | vm_map_copy_t copy; |
6267 | unsigned int size; |
6268 | |
6269 | size = s->getLength(); |
6270 | kr = mach_vm_allocate_kernel(map: kernel_map, addr: &data, size, VM_FLAGS_ANYWHERE, VM_KERN_MEMORY_IOKIT); |
6271 | if (kr == kIOReturnSuccess) { |
6272 | bcopy(src: s->text(), dst: (void *)data, n: size); |
6273 | kr = vm_map_copyin(src_map: kernel_map, src_addr: data, len: size, src_destroy: true, copy_result: ©); |
6274 | *outData = (char *)copy; |
6275 | *outDataCount = size; |
6276 | } |
6277 | } |
6278 | |
6279 | s->release(); |
6280 | |
6281 | return kr; |
6282 | } |
6283 | |
6284 | /* Routine io_catalog_get_gen_count */ |
6285 | kern_return_t |
6286 | is_io_catalog_get_gen_count( |
6287 | mach_port_t main_port, |
6288 | uint32_t *genCount) |
6289 | { |
6290 | if (main_port != main_device_port) { |
6291 | return kIOReturnNotPrivileged; |
6292 | } |
6293 | |
6294 | //printf("io_catalog_get_gen_count called.\n"); |
6295 | |
6296 | if (!genCount) { |
6297 | return kIOReturnBadArgument; |
6298 | } |
6299 | |
6300 | *genCount = gIOCatalogue->getGenerationCount(); |
6301 | |
6302 | return kIOReturnSuccess; |
6303 | } |
6304 | |
6305 | /* Routine io_catalog_module_loaded. |
6306 | * Is invoked from IOKitLib's IOCatalogueModuleLoaded(). Doesn't seem to be used. |
6307 | */ |
6308 | kern_return_t |
6309 | is_io_catalog_module_loaded( |
6310 | mach_port_t main_port, |
6311 | io_name_t name) |
6312 | { |
6313 | if (main_port != main_device_port) { |
6314 | return kIOReturnNotPrivileged; |
6315 | } |
6316 | |
6317 | //printf("io_catalog_module_loaded called. name %s\n", name); |
6318 | |
6319 | if (!name) { |
6320 | return kIOReturnBadArgument; |
6321 | } |
6322 | |
6323 | gIOCatalogue->moduleHasLoaded(name); |
6324 | |
6325 | return kIOReturnSuccess; |
6326 | } |
6327 | |
6328 | kern_return_t |
6329 | is_io_catalog_reset( |
6330 | mach_port_t main_port, |
6331 | uint32_t flag) |
6332 | { |
6333 | if (main_port != main_device_port) { |
6334 | return kIOReturnNotPrivileged; |
6335 | } |
6336 | |
6337 | switch (flag) { |
6338 | case kIOCatalogResetDefault: |
6339 | gIOCatalogue->reset(); |
6340 | break; |
6341 | |
6342 | default: |
6343 | return kIOReturnBadArgument; |
6344 | } |
6345 | |
6346 | return kIOReturnSuccess; |
6347 | } |
6348 | |
6349 | kern_return_t |
6350 | iokit_user_client_trap(struct iokit_user_client_trap_args *args) |
6351 | { |
6352 | kern_return_t result = kIOReturnBadArgument; |
6353 | IOUserClient * userClient; |
6354 | OSObject * object; |
6355 | uintptr_t ref; |
6356 | mach_port_name_t portName; |
6357 | |
6358 | ref = (uintptr_t) args->userClientRef; |
6359 | |
6360 | if ((ref == MACH_PORT_DEAD) || (ref == (uintptr_t) MACH_PORT_NULL)) { |
6361 | return kIOReturnBadArgument; |
6362 | } |
6363 | // kobject port names always have b0-1 set, so we use these bits as flags to |
6364 | // iokit_user_client_trap() |
6365 | // keep this up to date with ipc_entry_name_mask(); |
6366 | portName = (mach_port_name_t) (ref | 3); |
6367 | if (((1ULL << 32) & ref) || !(1 & ref)) { |
6368 | object = iokit_lookup_uext_ref_current_task(name: portName); |
6369 | if (object) { |
6370 | result = IOUserServerUEXTTrap(object, p1: args->p1, p2: args->p2, p3: args->p3, p4: args->p4, p5: args->p5, p6: args->p6); |
6371 | } |
6372 | OSSafeReleaseNULL(object); |
6373 | } else { |
6374 | io_object_t ref_current_task = iokit_lookup_connect_ref_current_task(name: (mach_port_name_t) ref); |
6375 | if ((userClient = OSDynamicCast(IOUserClient, ref_current_task))) { |
6376 | IOExternalTrap *trap = NULL; |
6377 | IOService *target = NULL; |
6378 | |
6379 | result = kIOReturnSuccess; |
6380 | io_filter_policy_t filterPolicy = userClient->filterForTask(task: current_task(), addFilterPolicy: 0); |
6381 | if (filterPolicy && gIOUCFilterCallbacks->io_filter_applier) { |
6382 | result = gIOUCFilterCallbacks->io_filter_applier(userClient, filterPolicy, io_filter_type_trap, args->index); |
6383 | } |
6384 | if (kIOReturnSuccess == result) { |
6385 | trap = userClient->getTargetAndTrapForIndex(targetP: &target, index: args->index); |
6386 | } |
6387 | if (trap && target) { |
6388 | IOTrap func; |
6389 | |
6390 | func = trap->func; |
6391 | |
6392 | if (func) { |
6393 | result = (target->*func)(args->p1, args->p2, args->p3, args->p4, args->p5, args->p6); |
6394 | } |
6395 | } |
6396 | |
6397 | iokit_remove_connect_reference(obj: userClient); |
6398 | } else { |
6399 | OSSafeReleaseNULL(ref_current_task); |
6400 | } |
6401 | } |
6402 | |
6403 | return result; |
6404 | } |
6405 | |
6406 | /* Routine io_device_tree_entry_exists_with_name */ |
6407 | kern_return_t |
6408 | is_io_device_tree_entry_exists_with_name( |
6409 | mach_port_t main_port, |
6410 | io_name_t name, |
6411 | boolean_t *exists ) |
6412 | { |
6413 | OSCollectionIterator *iter; |
6414 | |
6415 | if (main_port != main_device_port) { |
6416 | return kIOReturnNotPrivileged; |
6417 | } |
6418 | |
6419 | iter = IODTFindMatchingEntries(from: IORegistryEntry::getRegistryRoot(), options: kIODTRecursive, keys: name); |
6420 | *exists = iter && iter->getNextObject(); |
6421 | OSSafeReleaseNULL(iter); |
6422 | |
6423 | return kIOReturnSuccess; |
6424 | } |
6425 | } /* extern "C" */ |
6426 | |
6427 | IOReturn |
6428 | IOUserClient::callExternalMethod(uint32_t selector, IOExternalMethodArguments * args) |
6429 | { |
6430 | IOReturn ret; |
6431 | |
6432 | ipcEnter(locking: defaultLocking ? (defaultLockingSingleThreadExternalMethod ? kIPCLockWrite : kIPCLockRead) : kIPCLockNone); |
6433 | if (uc2022) { |
6434 | ret = ((IOUserClient2022 *) this)->externalMethod(selector, arguments: (IOExternalMethodArgumentsOpaque *) args); |
6435 | } else { |
6436 | ret = externalMethod(selector, arguments: args); |
6437 | } |
6438 | ipcExit(locking: defaultLocking ? (defaultLockingSingleThreadExternalMethod ? kIPCLockWrite : kIPCLockRead) : kIPCLockNone); |
6439 | |
6440 | return ret; |
6441 | } |
6442 | |
6443 | MIG_SERVER_ROUTINE IOReturn |
6444 | IOUserClient2022::externalMethod(uint32_t selector, IOExternalMethodArguments * arguments, |
6445 | IOExternalMethodDispatch *dispatch, |
6446 | OSObject *target, void *reference) |
6447 | { |
6448 | panic("wrong externalMethod for IOUserClient2022" ); |
6449 | } |
6450 | |
6451 | IOReturn |
6452 | IOUserClient2022::dispatchExternalMethod(uint32_t selector, IOExternalMethodArgumentsOpaque *arguments, |
6453 | const IOExternalMethodDispatch2022 dispatchArray[], size_t dispatchArrayCount, |
6454 | OSObject * target, void * reference) |
6455 | { |
6456 | IOReturn err; |
6457 | IOExternalMethodArguments * args = (typeof(args))arguments; |
6458 | const IOExternalMethodDispatch2022 * dispatch; |
6459 | |
6460 | if (!dispatchArray) { |
6461 | return kIOReturnError; |
6462 | } |
6463 | if (selector >= dispatchArrayCount) { |
6464 | return kIOReturnBadArgument; |
6465 | } |
6466 | dispatch = &dispatchArray[selector]; |
6467 | |
6468 | uint32_t count; |
6469 | count = dispatch->checkScalarInputCount; |
6470 | if ((kIOUCVariableStructureSize != count) && (count != args->scalarInputCount)) { |
6471 | return kIOReturnBadArgument; |
6472 | } |
6473 | |
6474 | count = dispatch->checkStructureInputSize; |
6475 | if ((kIOUCVariableStructureSize != count) |
6476 | && (count != ((args->structureInputDescriptor) |
6477 | ? args->structureInputDescriptor->getLength() : args->structureInputSize))) { |
6478 | return kIOReturnBadArgument; |
6479 | } |
6480 | |
6481 | count = dispatch->checkScalarOutputCount; |
6482 | if ((kIOUCVariableStructureSize != count) && (count != args->scalarOutputCount)) { |
6483 | return kIOReturnBadArgument; |
6484 | } |
6485 | |
6486 | count = dispatch->checkStructureOutputSize; |
6487 | if ((kIOUCVariableStructureSize != count) |
6488 | && (count != ((args->structureOutputDescriptor) |
6489 | ? args->structureOutputDescriptor->getLength() : args->structureOutputSize))) { |
6490 | return kIOReturnBadArgument; |
6491 | } |
6492 | |
6493 | if (args->asyncWakePort && !dispatch->allowAsync) { |
6494 | return kIOReturnBadArgument; |
6495 | } |
6496 | |
6497 | if (dispatch->checkEntitlement) { |
6498 | if (!IOCurrentTaskHasEntitlement(entitlement: dispatch->checkEntitlement)) { |
6499 | return kIOReturnNotPrivileged; |
6500 | } |
6501 | } |
6502 | |
6503 | if (dispatch->function) { |
6504 | err = (*dispatch->function)(target, reference, args); |
6505 | } else { |
6506 | err = kIOReturnNoCompletion; /* implementer can dispatch */ |
6507 | } |
6508 | return err; |
6509 | } |
6510 | |
6511 | IOReturn |
6512 | IOUserClient::externalMethod( uint32_t selector, IOExternalMethodArguments * args, |
6513 | IOExternalMethodDispatch * dispatch, OSObject * target, void * reference ) |
6514 | { |
6515 | IOReturn err; |
6516 | IOService * object; |
6517 | IOByteCount structureOutputSize; |
6518 | |
6519 | if (dispatch) { |
6520 | uint32_t count; |
6521 | count = dispatch->checkScalarInputCount; |
6522 | if ((kIOUCVariableStructureSize != count) && (count != args->scalarInputCount)) { |
6523 | return kIOReturnBadArgument; |
6524 | } |
6525 | |
6526 | count = dispatch->checkStructureInputSize; |
6527 | if ((kIOUCVariableStructureSize != count) |
6528 | && (count != ((args->structureInputDescriptor) |
6529 | ? args->structureInputDescriptor->getLength() : args->structureInputSize))) { |
6530 | return kIOReturnBadArgument; |
6531 | } |
6532 | |
6533 | count = dispatch->checkScalarOutputCount; |
6534 | if ((kIOUCVariableStructureSize != count) && (count != args->scalarOutputCount)) { |
6535 | return kIOReturnBadArgument; |
6536 | } |
6537 | |
6538 | count = dispatch->checkStructureOutputSize; |
6539 | if ((kIOUCVariableStructureSize != count) |
6540 | && (count != ((args->structureOutputDescriptor) |
6541 | ? args->structureOutputDescriptor->getLength() : args->structureOutputSize))) { |
6542 | return kIOReturnBadArgument; |
6543 | } |
6544 | |
6545 | if (dispatch->function) { |
6546 | err = (*dispatch->function)(target, reference, args); |
6547 | } else { |
6548 | err = kIOReturnNoCompletion; /* implementer can dispatch */ |
6549 | } |
6550 | return err; |
6551 | } |
6552 | |
6553 | |
6554 | // pre-Leopard API's don't do ool structs |
6555 | if (args->structureInputDescriptor || args->structureOutputDescriptor) { |
6556 | err = kIOReturnIPCError; |
6557 | return err; |
6558 | } |
6559 | |
6560 | structureOutputSize = args->structureOutputSize; |
6561 | |
6562 | if (args->asyncWakePort) { |
6563 | IOExternalAsyncMethod * method; |
6564 | object = NULL; |
6565 | if (!(method = getAsyncTargetAndMethodForIndex(targetP: &object, index: selector)) || !object) { |
6566 | return kIOReturnUnsupported; |
6567 | } |
6568 | |
6569 | if (kIOUCForegroundOnly & method->flags) { |
6570 | if (task_is_gpu_denied(task: current_task())) { |
6571 | return kIOReturnNotPermitted; |
6572 | } |
6573 | } |
6574 | |
6575 | switch (method->flags & kIOUCTypeMask) { |
6576 | case kIOUCScalarIStructI: |
6577 | err = shim_io_async_method_scalarI_structureI( method, object, |
6578 | asyncWakePort: args->asyncWakePort, asyncReference: args->asyncReference, asyncReferenceCount: args->asyncReferenceCount, |
6579 | input: args->scalarInput, inputCount: args->scalarInputCount, |
6580 | inputStruct: (char *)args->structureInput, inputStructCount: args->structureInputSize ); |
6581 | break; |
6582 | |
6583 | case kIOUCScalarIScalarO: |
6584 | err = shim_io_async_method_scalarI_scalarO( method, object, |
6585 | asyncWakePort: args->asyncWakePort, asyncReference: args->asyncReference, asyncReferenceCount: args->asyncReferenceCount, |
6586 | input: args->scalarInput, inputCount: args->scalarInputCount, |
6587 | output: args->scalarOutput, outputCount: &args->scalarOutputCount ); |
6588 | break; |
6589 | |
6590 | case kIOUCScalarIStructO: |
6591 | err = shim_io_async_method_scalarI_structureO( method, object, |
6592 | asyncWakePort: args->asyncWakePort, asyncReference: args->asyncReference, asyncReferenceCount: args->asyncReferenceCount, |
6593 | input: args->scalarInput, inputCount: args->scalarInputCount, |
6594 | output: (char *) args->structureOutput, outputCount: &args->structureOutputSize ); |
6595 | break; |
6596 | |
6597 | |
6598 | case kIOUCStructIStructO: |
6599 | err = shim_io_async_method_structureI_structureO( method, object, |
6600 | asyncWakePort: args->asyncWakePort, asyncReference: args->asyncReference, asyncReferenceCount: args->asyncReferenceCount, |
6601 | input: (char *)args->structureInput, inputCount: args->structureInputSize, |
6602 | output: (char *) args->structureOutput, outputCount: &args->structureOutputSize ); |
6603 | break; |
6604 | |
6605 | default: |
6606 | err = kIOReturnBadArgument; |
6607 | break; |
6608 | } |
6609 | } else { |
6610 | IOExternalMethod * method; |
6611 | object = NULL; |
6612 | if (!(method = getTargetAndMethodForIndex(targetP: &object, index: selector)) || !object) { |
6613 | return kIOReturnUnsupported; |
6614 | } |
6615 | |
6616 | if (kIOUCForegroundOnly & method->flags) { |
6617 | if (task_is_gpu_denied(task: current_task())) { |
6618 | return kIOReturnNotPermitted; |
6619 | } |
6620 | } |
6621 | |
6622 | switch (method->flags & kIOUCTypeMask) { |
6623 | case kIOUCScalarIStructI: |
6624 | err = shim_io_connect_method_scalarI_structureI( method, object, |
6625 | input: args->scalarInput, inputCount: args->scalarInputCount, |
6626 | inputStruct: (char *) args->structureInput, inputStructCount: args->structureInputSize ); |
6627 | break; |
6628 | |
6629 | case kIOUCScalarIScalarO: |
6630 | err = shim_io_connect_method_scalarI_scalarO( method, object, |
6631 | input: args->scalarInput, inputCount: args->scalarInputCount, |
6632 | output: args->scalarOutput, outputCount: &args->scalarOutputCount ); |
6633 | break; |
6634 | |
6635 | case kIOUCScalarIStructO: |
6636 | err = shim_io_connect_method_scalarI_structureO( method, object, |
6637 | input: args->scalarInput, inputCount: args->scalarInputCount, |
6638 | output: (char *) args->structureOutput, outputCount: &structureOutputSize ); |
6639 | break; |
6640 | |
6641 | |
6642 | case kIOUCStructIStructO: |
6643 | err = shim_io_connect_method_structureI_structureO( method, object, |
6644 | input: (char *) args->structureInput, inputCount: args->structureInputSize, |
6645 | output: (char *) args->structureOutput, outputCount: &structureOutputSize ); |
6646 | break; |
6647 | |
6648 | default: |
6649 | err = kIOReturnBadArgument; |
6650 | break; |
6651 | } |
6652 | } |
6653 | |
6654 | if (structureOutputSize > UINT_MAX) { |
6655 | structureOutputSize = 0; |
6656 | err = kIOReturnBadArgument; |
6657 | } |
6658 | |
6659 | args->structureOutputSize = ((typeof(args->structureOutputSize))structureOutputSize); |
6660 | |
6661 | return err; |
6662 | } |
6663 | |
6664 | IOReturn |
6665 | IOUserClient::registerFilterCallbacks(const struct io_filter_callbacks *callbacks, size_t size) |
6666 | { |
6667 | if (size < sizeof(*callbacks)) { |
6668 | return kIOReturnBadArgument; |
6669 | } |
6670 | if (!OSCompareAndSwapPtr(NULL, __DECONST(void *, callbacks), &gIOUCFilterCallbacks)) { |
6671 | return kIOReturnBusy; |
6672 | } |
6673 | return kIOReturnSuccess; |
6674 | } |
6675 | |
6676 | |
6677 | OSMetaClassDefineReservedUnused(IOUserClient, 0); |
6678 | OSMetaClassDefineReservedUnused(IOUserClient, 1); |
6679 | OSMetaClassDefineReservedUnused(IOUserClient, 2); |
6680 | OSMetaClassDefineReservedUnused(IOUserClient, 3); |
6681 | OSMetaClassDefineReservedUnused(IOUserClient, 4); |
6682 | OSMetaClassDefineReservedUnused(IOUserClient, 5); |
6683 | OSMetaClassDefineReservedUnused(IOUserClient, 6); |
6684 | OSMetaClassDefineReservedUnused(IOUserClient, 7); |
6685 | OSMetaClassDefineReservedUnused(IOUserClient, 8); |
6686 | OSMetaClassDefineReservedUnused(IOUserClient, 9); |
6687 | OSMetaClassDefineReservedUnused(IOUserClient, 10); |
6688 | OSMetaClassDefineReservedUnused(IOUserClient, 11); |
6689 | OSMetaClassDefineReservedUnused(IOUserClient, 12); |
6690 | OSMetaClassDefineReservedUnused(IOUserClient, 13); |
6691 | OSMetaClassDefineReservedUnused(IOUserClient, 14); |
6692 | OSMetaClassDefineReservedUnused(IOUserClient, 15); |
6693 | |
6694 | OSMetaClassDefineReservedUnused(IOUserClient2022, 0); |
6695 | OSMetaClassDefineReservedUnused(IOUserClient2022, 1); |
6696 | OSMetaClassDefineReservedUnused(IOUserClient2022, 2); |
6697 | OSMetaClassDefineReservedUnused(IOUserClient2022, 3); |
6698 | |