xref: /xnu-8792.81.2/iokit/bsddev/IOKitBSDInit.cpp (revision 19c3b8c28c31cb8130e034cfb5df6bf9ba342d90)
1*19c3b8c2SApple OSS Distributions /*
2*19c3b8c2SApple OSS Distributions  * Copyright (c) 1998-2021 Apple Inc. All rights reserved.
3*19c3b8c2SApple OSS Distributions  *
4*19c3b8c2SApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5*19c3b8c2SApple OSS Distributions  *
6*19c3b8c2SApple OSS Distributions  * This file contains Original Code and/or Modifications of Original Code
7*19c3b8c2SApple OSS Distributions  * as defined in and that are subject to the Apple Public Source License
8*19c3b8c2SApple OSS Distributions  * Version 2.0 (the 'License'). You may not use this file except in
9*19c3b8c2SApple OSS Distributions  * compliance with the License. The rights granted to you under the License
10*19c3b8c2SApple OSS Distributions  * may not be used to create, or enable the creation or redistribution of,
11*19c3b8c2SApple OSS Distributions  * unlawful or unlicensed copies of an Apple operating system, or to
12*19c3b8c2SApple OSS Distributions  * circumvent, violate, or enable the circumvention or violation of, any
13*19c3b8c2SApple OSS Distributions  * terms of an Apple operating system software license agreement.
14*19c3b8c2SApple OSS Distributions  *
15*19c3b8c2SApple OSS Distributions  * Please obtain a copy of the License at
16*19c3b8c2SApple OSS Distributions  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17*19c3b8c2SApple OSS Distributions  *
18*19c3b8c2SApple OSS Distributions  * The Original Code and all software distributed under the License are
19*19c3b8c2SApple OSS Distributions  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20*19c3b8c2SApple OSS Distributions  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21*19c3b8c2SApple OSS Distributions  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22*19c3b8c2SApple OSS Distributions  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23*19c3b8c2SApple OSS Distributions  * Please see the License for the specific language governing rights and
24*19c3b8c2SApple OSS Distributions  * limitations under the License.
25*19c3b8c2SApple OSS Distributions  *
26*19c3b8c2SApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27*19c3b8c2SApple OSS Distributions  */
28*19c3b8c2SApple OSS Distributions #include <IOKit/IOBSD.h>
29*19c3b8c2SApple OSS Distributions #include <IOKit/IOLib.h>
30*19c3b8c2SApple OSS Distributions #include <IOKit/IOService.h>
31*19c3b8c2SApple OSS Distributions #include <IOKit/IOCatalogue.h>
32*19c3b8c2SApple OSS Distributions #include <IOKit/IODeviceTreeSupport.h>
33*19c3b8c2SApple OSS Distributions #include <IOKit/IOKitKeys.h>
34*19c3b8c2SApple OSS Distributions #include <IOKit/IONVRAM.h>
35*19c3b8c2SApple OSS Distributions #include <IOKit/IOPlatformExpert.h>
36*19c3b8c2SApple OSS Distributions #include <IOKit/IOUserClient.h>
37*19c3b8c2SApple OSS Distributions #include <libkern/c++/OSAllocation.h>
38*19c3b8c2SApple OSS Distributions 
39*19c3b8c2SApple OSS Distributions extern "C" {
40*19c3b8c2SApple OSS Distributions #include <libkern/amfi/amfi.h>
41*19c3b8c2SApple OSS Distributions #include <sys/codesign.h>
42*19c3b8c2SApple OSS Distributions #include <vm/pmap.h>
43*19c3b8c2SApple OSS Distributions #include <vm/vm_map.h>
44*19c3b8c2SApple OSS Distributions #include <pexpert/pexpert.h>
45*19c3b8c2SApple OSS Distributions #include <kern/clock.h>
46*19c3b8c2SApple OSS Distributions #if CONFIG_KDP_INTERACTIVE_DEBUGGING
47*19c3b8c2SApple OSS Distributions #include <kern/debug.h>
48*19c3b8c2SApple OSS Distributions #endif
49*19c3b8c2SApple OSS Distributions #include <mach/machine.h>
50*19c3b8c2SApple OSS Distributions #include <uuid/uuid.h>
51*19c3b8c2SApple OSS Distributions #include <sys/vnode_internal.h>
52*19c3b8c2SApple OSS Distributions #include <sys/mount.h>
53*19c3b8c2SApple OSS Distributions #include <corecrypto/ccsha2.h>
54*19c3b8c2SApple OSS Distributions 
55*19c3b8c2SApple OSS Distributions // how long to wait for matching root device, secs
56*19c3b8c2SApple OSS Distributions #if DEBUG
57*19c3b8c2SApple OSS Distributions #define ROOTDEVICETIMEOUT       120
58*19c3b8c2SApple OSS Distributions #else
59*19c3b8c2SApple OSS Distributions #define ROOTDEVICETIMEOUT       60
60*19c3b8c2SApple OSS Distributions #endif
61*19c3b8c2SApple OSS Distributions 
62*19c3b8c2SApple OSS Distributions extern dev_t mdevadd(int devid, uint64_t base, unsigned int size, int phys);
63*19c3b8c2SApple OSS Distributions extern dev_t mdevlookup(int devid);
64*19c3b8c2SApple OSS Distributions extern void mdevremoveall(void);
65*19c3b8c2SApple OSS Distributions extern int mdevgetrange(int devid, uint64_t *base, uint64_t *size);
66*19c3b8c2SApple OSS Distributions extern void di_root_ramfile(IORegistryEntry * entry);
67*19c3b8c2SApple OSS Distributions extern int IODTGetDefault(const char *key, void *infoAddr, unsigned int infoSize);
68*19c3b8c2SApple OSS Distributions extern boolean_t cpuid_vmm_present(void);
69*19c3b8c2SApple OSS Distributions 
70*19c3b8c2SApple OSS Distributions #define ROUNDUP(a, b) (((a) + ((b) - 1)) & (~((b) - 1)))
71*19c3b8c2SApple OSS Distributions 
72*19c3b8c2SApple OSS Distributions #define IOPOLLED_COREFILE       (CONFIG_KDP_INTERACTIVE_DEBUGGING)
73*19c3b8c2SApple OSS Distributions 
74*19c3b8c2SApple OSS Distributions #if defined(XNU_TARGET_OS_BRIDGE)
75*19c3b8c2SApple OSS Distributions #define kIOCoreDumpPath         "/private/var/internal/kernelcore"
76*19c3b8c2SApple OSS Distributions #elif defined(XNU_TARGET_OS_OSX)
77*19c3b8c2SApple OSS Distributions #define kIOCoreDumpPath         "/System/Volumes/VM/kernelcore"
78*19c3b8c2SApple OSS Distributions #else
79*19c3b8c2SApple OSS Distributions #define kIOCoreDumpPath         "/private/var/vm/kernelcore"
80*19c3b8c2SApple OSS Distributions #endif
81*19c3b8c2SApple OSS Distributions 
82*19c3b8c2SApple OSS Distributions #define SYSTEM_NVRAM_PREFIX     "40A0DDD2-77F8-4392-B4A3-1E7304206516:"
83*19c3b8c2SApple OSS Distributions 
84*19c3b8c2SApple OSS Distributions #if CONFIG_KDP_INTERACTIVE_DEBUGGING
85*19c3b8c2SApple OSS Distributions /*
86*19c3b8c2SApple OSS Distributions  * Touched by IOFindBSDRoot() if a RAMDisk is used for the root device.
87*19c3b8c2SApple OSS Distributions  */
88*19c3b8c2SApple OSS Distributions extern uint64_t kdp_core_ramdisk_addr;
89*19c3b8c2SApple OSS Distributions extern uint64_t kdp_core_ramdisk_size;
90*19c3b8c2SApple OSS Distributions 
91*19c3b8c2SApple OSS Distributions /*
92*19c3b8c2SApple OSS Distributions  * A callback to indicate that the polled-mode corefile is now available.
93*19c3b8c2SApple OSS Distributions  */
94*19c3b8c2SApple OSS Distributions extern kern_return_t kdp_core_polled_io_polled_file_available(IOCoreFileAccessCallback access_data, void *access_context, void *recipient_context);
95*19c3b8c2SApple OSS Distributions 
96*19c3b8c2SApple OSS Distributions /*
97*19c3b8c2SApple OSS Distributions  * A callback to indicate that the polled-mode corefile is no longer available.
98*19c3b8c2SApple OSS Distributions  */
99*19c3b8c2SApple OSS Distributions extern kern_return_t kdp_core_polled_io_polled_file_unavailable(void);
100*19c3b8c2SApple OSS Distributions #endif
101*19c3b8c2SApple OSS Distributions 
102*19c3b8c2SApple OSS Distributions #if IOPOLLED_COREFILE
103*19c3b8c2SApple OSS Distributions static void IOOpenPolledCoreFile(thread_call_param_t __unused, thread_call_param_t corefilename);
104*19c3b8c2SApple OSS Distributions 
105*19c3b8c2SApple OSS Distributions thread_call_t corefile_open_call = NULL;
106*19c3b8c2SApple OSS Distributions #endif
107*19c3b8c2SApple OSS Distributions 
108*19c3b8c2SApple OSS Distributions kern_return_t
IOKitBSDInit(void)109*19c3b8c2SApple OSS Distributions IOKitBSDInit( void )
110*19c3b8c2SApple OSS Distributions {
111*19c3b8c2SApple OSS Distributions 	IOService::publishResource("IOBSD");
112*19c3b8c2SApple OSS Distributions 
113*19c3b8c2SApple OSS Distributions #if IOPOLLED_COREFILE
114*19c3b8c2SApple OSS Distributions 	corefile_open_call = thread_call_allocate_with_options(IOOpenPolledCoreFile, NULL, THREAD_CALL_PRIORITY_KERNEL, THREAD_CALL_OPTIONS_ONCE);
115*19c3b8c2SApple OSS Distributions #endif
116*19c3b8c2SApple OSS Distributions 
117*19c3b8c2SApple OSS Distributions 	return kIOReturnSuccess;
118*19c3b8c2SApple OSS Distributions }
119*19c3b8c2SApple OSS Distributions 
120*19c3b8c2SApple OSS Distributions void
IOServicePublishResource(const char * property,boolean_t value)121*19c3b8c2SApple OSS Distributions IOServicePublishResource( const char * property, boolean_t value )
122*19c3b8c2SApple OSS Distributions {
123*19c3b8c2SApple OSS Distributions 	if (value) {
124*19c3b8c2SApple OSS Distributions 		IOService::publishResource( property, kOSBooleanTrue );
125*19c3b8c2SApple OSS Distributions 	} else {
126*19c3b8c2SApple OSS Distributions 		IOService::getResourceService()->removeProperty( property );
127*19c3b8c2SApple OSS Distributions 	}
128*19c3b8c2SApple OSS Distributions }
129*19c3b8c2SApple OSS Distributions 
130*19c3b8c2SApple OSS Distributions boolean_t
IOServiceWaitForMatchingResource(const char * property,uint64_t timeout)131*19c3b8c2SApple OSS Distributions IOServiceWaitForMatchingResource( const char * property, uint64_t timeout )
132*19c3b8c2SApple OSS Distributions {
133*19c3b8c2SApple OSS Distributions 	OSDictionary *      dict = NULL;
134*19c3b8c2SApple OSS Distributions 	IOService *         match = NULL;
135*19c3b8c2SApple OSS Distributions 	boolean_t           found = false;
136*19c3b8c2SApple OSS Distributions 
137*19c3b8c2SApple OSS Distributions 	do {
138*19c3b8c2SApple OSS Distributions 		dict = IOService::resourceMatching( property );
139*19c3b8c2SApple OSS Distributions 		if (!dict) {
140*19c3b8c2SApple OSS Distributions 			continue;
141*19c3b8c2SApple OSS Distributions 		}
142*19c3b8c2SApple OSS Distributions 		match = IOService::waitForMatchingService( dict, timeout );
143*19c3b8c2SApple OSS Distributions 		if (match) {
144*19c3b8c2SApple OSS Distributions 			found = true;
145*19c3b8c2SApple OSS Distributions 		}
146*19c3b8c2SApple OSS Distributions 	} while (false);
147*19c3b8c2SApple OSS Distributions 
148*19c3b8c2SApple OSS Distributions 	if (dict) {
149*19c3b8c2SApple OSS Distributions 		dict->release();
150*19c3b8c2SApple OSS Distributions 	}
151*19c3b8c2SApple OSS Distributions 	if (match) {
152*19c3b8c2SApple OSS Distributions 		match->release();
153*19c3b8c2SApple OSS Distributions 	}
154*19c3b8c2SApple OSS Distributions 
155*19c3b8c2SApple OSS Distributions 	return found;
156*19c3b8c2SApple OSS Distributions }
157*19c3b8c2SApple OSS Distributions 
158*19c3b8c2SApple OSS Distributions boolean_t
IOCatalogueMatchingDriversPresent(const char * property)159*19c3b8c2SApple OSS Distributions IOCatalogueMatchingDriversPresent( const char * property )
160*19c3b8c2SApple OSS Distributions {
161*19c3b8c2SApple OSS Distributions 	OSDictionary *      dict = NULL;
162*19c3b8c2SApple OSS Distributions 	OSOrderedSet *      set = NULL;
163*19c3b8c2SApple OSS Distributions 	SInt32              generationCount = 0;
164*19c3b8c2SApple OSS Distributions 	boolean_t           found = false;
165*19c3b8c2SApple OSS Distributions 
166*19c3b8c2SApple OSS Distributions 	do {
167*19c3b8c2SApple OSS Distributions 		dict = OSDictionary::withCapacity(1);
168*19c3b8c2SApple OSS Distributions 		if (!dict) {
169*19c3b8c2SApple OSS Distributions 			continue;
170*19c3b8c2SApple OSS Distributions 		}
171*19c3b8c2SApple OSS Distributions 		dict->setObject( property, kOSBooleanTrue );
172*19c3b8c2SApple OSS Distributions 		set = gIOCatalogue->findDrivers( dict, &generationCount );
173*19c3b8c2SApple OSS Distributions 		if (set && (set->getCount() > 0)) {
174*19c3b8c2SApple OSS Distributions 			found = true;
175*19c3b8c2SApple OSS Distributions 		}
176*19c3b8c2SApple OSS Distributions 	} while (false);
177*19c3b8c2SApple OSS Distributions 
178*19c3b8c2SApple OSS Distributions 	if (dict) {
179*19c3b8c2SApple OSS Distributions 		dict->release();
180*19c3b8c2SApple OSS Distributions 	}
181*19c3b8c2SApple OSS Distributions 	if (set) {
182*19c3b8c2SApple OSS Distributions 		set->release();
183*19c3b8c2SApple OSS Distributions 	}
184*19c3b8c2SApple OSS Distributions 
185*19c3b8c2SApple OSS Distributions 	return found;
186*19c3b8c2SApple OSS Distributions }
187*19c3b8c2SApple OSS Distributions 
188*19c3b8c2SApple OSS Distributions OSDictionary *
IOBSDNameMatching(const char * name)189*19c3b8c2SApple OSS Distributions IOBSDNameMatching( const char * name )
190*19c3b8c2SApple OSS Distributions {
191*19c3b8c2SApple OSS Distributions 	OSDictionary *      dict;
192*19c3b8c2SApple OSS Distributions 	const OSSymbol *    str = NULL;
193*19c3b8c2SApple OSS Distributions 
194*19c3b8c2SApple OSS Distributions 	do {
195*19c3b8c2SApple OSS Distributions 		dict = IOService::serviceMatching( gIOServiceKey );
196*19c3b8c2SApple OSS Distributions 		if (!dict) {
197*19c3b8c2SApple OSS Distributions 			continue;
198*19c3b8c2SApple OSS Distributions 		}
199*19c3b8c2SApple OSS Distributions 		str = OSSymbol::withCString( name );
200*19c3b8c2SApple OSS Distributions 		if (!str) {
201*19c3b8c2SApple OSS Distributions 			continue;
202*19c3b8c2SApple OSS Distributions 		}
203*19c3b8c2SApple OSS Distributions 		dict->setObject( kIOBSDNameKey, (OSObject *) str );
204*19c3b8c2SApple OSS Distributions 		str->release();
205*19c3b8c2SApple OSS Distributions 
206*19c3b8c2SApple OSS Distributions 		return dict;
207*19c3b8c2SApple OSS Distributions 	} while (false);
208*19c3b8c2SApple OSS Distributions 
209*19c3b8c2SApple OSS Distributions 	if (dict) {
210*19c3b8c2SApple OSS Distributions 		dict->release();
211*19c3b8c2SApple OSS Distributions 	}
212*19c3b8c2SApple OSS Distributions 	if (str) {
213*19c3b8c2SApple OSS Distributions 		str->release();
214*19c3b8c2SApple OSS Distributions 	}
215*19c3b8c2SApple OSS Distributions 
216*19c3b8c2SApple OSS Distributions 	return NULL;
217*19c3b8c2SApple OSS Distributions }
218*19c3b8c2SApple OSS Distributions 
219*19c3b8c2SApple OSS Distributions OSDictionary *
IOUUIDMatching(void)220*19c3b8c2SApple OSS Distributions IOUUIDMatching( void )
221*19c3b8c2SApple OSS Distributions {
222*19c3b8c2SApple OSS Distributions 	return IOService::resourceMatching( "boot-uuid-media" );
223*19c3b8c2SApple OSS Distributions }
224*19c3b8c2SApple OSS Distributions 
225*19c3b8c2SApple OSS Distributions OSDictionary *
IONetworkNamePrefixMatching(const char * prefix)226*19c3b8c2SApple OSS Distributions IONetworkNamePrefixMatching( const char * prefix )
227*19c3b8c2SApple OSS Distributions {
228*19c3b8c2SApple OSS Distributions 	OSDictionary *       matching;
229*19c3b8c2SApple OSS Distributions 	OSDictionary *   propDict = NULL;
230*19c3b8c2SApple OSS Distributions 	const OSSymbol * str      = NULL;
231*19c3b8c2SApple OSS Distributions 	char networkType[128];
232*19c3b8c2SApple OSS Distributions 
233*19c3b8c2SApple OSS Distributions 	do {
234*19c3b8c2SApple OSS Distributions 		matching = IOService::serviceMatching( "IONetworkInterface" );
235*19c3b8c2SApple OSS Distributions 		if (matching == NULL) {
236*19c3b8c2SApple OSS Distributions 			continue;
237*19c3b8c2SApple OSS Distributions 		}
238*19c3b8c2SApple OSS Distributions 
239*19c3b8c2SApple OSS Distributions 		propDict = OSDictionary::withCapacity(1);
240*19c3b8c2SApple OSS Distributions 		if (propDict == NULL) {
241*19c3b8c2SApple OSS Distributions 			continue;
242*19c3b8c2SApple OSS Distributions 		}
243*19c3b8c2SApple OSS Distributions 
244*19c3b8c2SApple OSS Distributions 		str = OSSymbol::withCString( prefix );
245*19c3b8c2SApple OSS Distributions 		if (str == NULL) {
246*19c3b8c2SApple OSS Distributions 			continue;
247*19c3b8c2SApple OSS Distributions 		}
248*19c3b8c2SApple OSS Distributions 
249*19c3b8c2SApple OSS Distributions 		propDict->setObject( "IOInterfaceNamePrefix", (OSObject *) str );
250*19c3b8c2SApple OSS Distributions 		str->release();
251*19c3b8c2SApple OSS Distributions 		str = NULL;
252*19c3b8c2SApple OSS Distributions 
253*19c3b8c2SApple OSS Distributions 		// see if we're contrained to netroot off of specific network type
254*19c3b8c2SApple OSS Distributions 		if (PE_parse_boot_argn( "network-type", networkType, 128 )) {
255*19c3b8c2SApple OSS Distributions 			str = OSSymbol::withCString( networkType );
256*19c3b8c2SApple OSS Distributions 			if (str) {
257*19c3b8c2SApple OSS Distributions 				propDict->setObject( "IONetworkRootType", str);
258*19c3b8c2SApple OSS Distributions 				str->release();
259*19c3b8c2SApple OSS Distributions 				str = NULL;
260*19c3b8c2SApple OSS Distributions 			}
261*19c3b8c2SApple OSS Distributions 		}
262*19c3b8c2SApple OSS Distributions 
263*19c3b8c2SApple OSS Distributions 		if (matching->setObject( gIOPropertyMatchKey,
264*19c3b8c2SApple OSS Distributions 		    (OSObject *) propDict ) != true) {
265*19c3b8c2SApple OSS Distributions 			continue;
266*19c3b8c2SApple OSS Distributions 		}
267*19c3b8c2SApple OSS Distributions 
268*19c3b8c2SApple OSS Distributions 		propDict->release();
269*19c3b8c2SApple OSS Distributions 		propDict = NULL;
270*19c3b8c2SApple OSS Distributions 
271*19c3b8c2SApple OSS Distributions 		return matching;
272*19c3b8c2SApple OSS Distributions 	} while (false);
273*19c3b8c2SApple OSS Distributions 
274*19c3b8c2SApple OSS Distributions 	if (matching) {
275*19c3b8c2SApple OSS Distributions 		matching->release();
276*19c3b8c2SApple OSS Distributions 	}
277*19c3b8c2SApple OSS Distributions 	if (propDict) {
278*19c3b8c2SApple OSS Distributions 		propDict->release();
279*19c3b8c2SApple OSS Distributions 	}
280*19c3b8c2SApple OSS Distributions 	if (str) {
281*19c3b8c2SApple OSS Distributions 		str->release();
282*19c3b8c2SApple OSS Distributions 	}
283*19c3b8c2SApple OSS Distributions 
284*19c3b8c2SApple OSS Distributions 	return NULL;
285*19c3b8c2SApple OSS Distributions }
286*19c3b8c2SApple OSS Distributions 
287*19c3b8c2SApple OSS Distributions static bool
IORegisterNetworkInterface(IOService * netif)288*19c3b8c2SApple OSS Distributions IORegisterNetworkInterface( IOService * netif )
289*19c3b8c2SApple OSS Distributions {
290*19c3b8c2SApple OSS Distributions 	// A network interface is typically named and registered
291*19c3b8c2SApple OSS Distributions 	// with BSD after receiving a request from a user space
292*19c3b8c2SApple OSS Distributions 	// "namer". However, for cases when the system needs to
293*19c3b8c2SApple OSS Distributions 	// root from the network, this registration task must be
294*19c3b8c2SApple OSS Distributions 	// done inside the kernel and completed before the root
295*19c3b8c2SApple OSS Distributions 	// device is handed to BSD.
296*19c3b8c2SApple OSS Distributions 
297*19c3b8c2SApple OSS Distributions 	IOService *    stack;
298*19c3b8c2SApple OSS Distributions 	OSNumber *     zero    = NULL;
299*19c3b8c2SApple OSS Distributions 	OSString *     path    = NULL;
300*19c3b8c2SApple OSS Distributions 	OSDictionary * dict    = NULL;
301*19c3b8c2SApple OSS Distributions 	OSDataAllocation<char> pathBuf;
302*19c3b8c2SApple OSS Distributions 	int            len;
303*19c3b8c2SApple OSS Distributions 	enum { kMaxPathLen = 512 };
304*19c3b8c2SApple OSS Distributions 
305*19c3b8c2SApple OSS Distributions 	do {
306*19c3b8c2SApple OSS Distributions 		stack = IOService::waitForService(
307*19c3b8c2SApple OSS Distributions 			IOService::serviceMatching("IONetworkStack"));
308*19c3b8c2SApple OSS Distributions 		if (stack == NULL) {
309*19c3b8c2SApple OSS Distributions 			break;
310*19c3b8c2SApple OSS Distributions 		}
311*19c3b8c2SApple OSS Distributions 
312*19c3b8c2SApple OSS Distributions 		dict = OSDictionary::withCapacity(3);
313*19c3b8c2SApple OSS Distributions 		if (dict == NULL) {
314*19c3b8c2SApple OSS Distributions 			break;
315*19c3b8c2SApple OSS Distributions 		}
316*19c3b8c2SApple OSS Distributions 
317*19c3b8c2SApple OSS Distributions 		zero = OSNumber::withNumber((UInt64) 0, 32);
318*19c3b8c2SApple OSS Distributions 		if (zero == NULL) {
319*19c3b8c2SApple OSS Distributions 			break;
320*19c3b8c2SApple OSS Distributions 		}
321*19c3b8c2SApple OSS Distributions 
322*19c3b8c2SApple OSS Distributions 		pathBuf = OSDataAllocation<char>( kMaxPathLen, OSAllocateMemory );
323*19c3b8c2SApple OSS Distributions 		if (!pathBuf) {
324*19c3b8c2SApple OSS Distributions 			break;
325*19c3b8c2SApple OSS Distributions 		}
326*19c3b8c2SApple OSS Distributions 
327*19c3b8c2SApple OSS Distributions 		len = kMaxPathLen;
328*19c3b8c2SApple OSS Distributions 		if (netif->getPath( pathBuf.data(), &len, gIOServicePlane )
329*19c3b8c2SApple OSS Distributions 		    == false) {
330*19c3b8c2SApple OSS Distributions 			break;
331*19c3b8c2SApple OSS Distributions 		}
332*19c3b8c2SApple OSS Distributions 
333*19c3b8c2SApple OSS Distributions 		path = OSString::withCStringNoCopy(pathBuf.data());
334*19c3b8c2SApple OSS Distributions 		if (path == NULL) {
335*19c3b8c2SApple OSS Distributions 			break;
336*19c3b8c2SApple OSS Distributions 		}
337*19c3b8c2SApple OSS Distributions 
338*19c3b8c2SApple OSS Distributions 		dict->setObject( "IOInterfaceUnit", zero );
339*19c3b8c2SApple OSS Distributions 		dict->setObject( kIOPathMatchKey, path );
340*19c3b8c2SApple OSS Distributions 
341*19c3b8c2SApple OSS Distributions 		stack->setProperties( dict );
342*19c3b8c2SApple OSS Distributions 	}while (false);
343*19c3b8c2SApple OSS Distributions 
344*19c3b8c2SApple OSS Distributions 	if (zero) {
345*19c3b8c2SApple OSS Distributions 		zero->release();
346*19c3b8c2SApple OSS Distributions 	}
347*19c3b8c2SApple OSS Distributions 	if (path) {
348*19c3b8c2SApple OSS Distributions 		path->release();
349*19c3b8c2SApple OSS Distributions 	}
350*19c3b8c2SApple OSS Distributions 	if (dict) {
351*19c3b8c2SApple OSS Distributions 		dict->release();
352*19c3b8c2SApple OSS Distributions 	}
353*19c3b8c2SApple OSS Distributions 
354*19c3b8c2SApple OSS Distributions 	return netif->getProperty( kIOBSDNameKey ) != NULL;
355*19c3b8c2SApple OSS Distributions }
356*19c3b8c2SApple OSS Distributions 
357*19c3b8c2SApple OSS Distributions OSDictionary *
IOOFPathMatching(const char * path,char * buf,int maxLen)358*19c3b8c2SApple OSS Distributions IOOFPathMatching( const char * path, char * buf, int maxLen )
359*19c3b8c2SApple OSS Distributions {
360*19c3b8c2SApple OSS Distributions 	OSDictionary *      matching = NULL;
361*19c3b8c2SApple OSS Distributions 	OSString *          str;
362*19c3b8c2SApple OSS Distributions 	char *              comp;
363*19c3b8c2SApple OSS Distributions 	int                 len;
364*19c3b8c2SApple OSS Distributions 
365*19c3b8c2SApple OSS Distributions 	do {
366*19c3b8c2SApple OSS Distributions 		len = ((int) strlen( kIODeviceTreePlane ":" ));
367*19c3b8c2SApple OSS Distributions 		maxLen -= len;
368*19c3b8c2SApple OSS Distributions 		if (maxLen <= 0) {
369*19c3b8c2SApple OSS Distributions 			continue;
370*19c3b8c2SApple OSS Distributions 		}
371*19c3b8c2SApple OSS Distributions 
372*19c3b8c2SApple OSS Distributions 		strlcpy( buf, kIODeviceTreePlane ":", len + 1 );
373*19c3b8c2SApple OSS Distributions 		comp = buf + len;
374*19c3b8c2SApple OSS Distributions 
375*19c3b8c2SApple OSS Distributions 		len = ((int) strnlen( path, INT_MAX ));
376*19c3b8c2SApple OSS Distributions 		maxLen -= len;
377*19c3b8c2SApple OSS Distributions 		if (maxLen <= 0) {
378*19c3b8c2SApple OSS Distributions 			continue;
379*19c3b8c2SApple OSS Distributions 		}
380*19c3b8c2SApple OSS Distributions 		strlcpy( comp, path, len + 1 );
381*19c3b8c2SApple OSS Distributions 
382*19c3b8c2SApple OSS Distributions 		matching = OSDictionary::withCapacity( 1 );
383*19c3b8c2SApple OSS Distributions 		if (!matching) {
384*19c3b8c2SApple OSS Distributions 			continue;
385*19c3b8c2SApple OSS Distributions 		}
386*19c3b8c2SApple OSS Distributions 
387*19c3b8c2SApple OSS Distributions 		str = OSString::withCString( buf );
388*19c3b8c2SApple OSS Distributions 		if (!str) {
389*19c3b8c2SApple OSS Distributions 			continue;
390*19c3b8c2SApple OSS Distributions 		}
391*19c3b8c2SApple OSS Distributions 		matching->setObject( kIOPathMatchKey, str );
392*19c3b8c2SApple OSS Distributions 		str->release();
393*19c3b8c2SApple OSS Distributions 
394*19c3b8c2SApple OSS Distributions 		return matching;
395*19c3b8c2SApple OSS Distributions 	} while (false);
396*19c3b8c2SApple OSS Distributions 
397*19c3b8c2SApple OSS Distributions 	if (matching) {
398*19c3b8c2SApple OSS Distributions 		matching->release();
399*19c3b8c2SApple OSS Distributions 	}
400*19c3b8c2SApple OSS Distributions 
401*19c3b8c2SApple OSS Distributions 	return NULL;
402*19c3b8c2SApple OSS Distributions }
403*19c3b8c2SApple OSS Distributions 
404*19c3b8c2SApple OSS Distributions static int didRam = 0;
405*19c3b8c2SApple OSS Distributions enum { kMaxPathBuf = 512, kMaxBootVar = 128 };
406*19c3b8c2SApple OSS Distributions 
407*19c3b8c2SApple OSS Distributions bool
IOGetBootUUID(char * uuid)408*19c3b8c2SApple OSS Distributions IOGetBootUUID(char *uuid)
409*19c3b8c2SApple OSS Distributions {
410*19c3b8c2SApple OSS Distributions 	IORegistryEntry *entry;
411*19c3b8c2SApple OSS Distributions 	OSData *uuid_data = NULL;
412*19c3b8c2SApple OSS Distributions 	bool result = false;
413*19c3b8c2SApple OSS Distributions 
414*19c3b8c2SApple OSS Distributions 	if ((entry = IORegistryEntry::fromPath("/chosen", gIODTPlane))) {
415*19c3b8c2SApple OSS Distributions 		uuid_data = (OSData *)entry->getProperty("boot-uuid");
416*19c3b8c2SApple OSS Distributions 		if (uuid_data) {
417*19c3b8c2SApple OSS Distributions 			unsigned int length = uuid_data->getLength();
418*19c3b8c2SApple OSS Distributions 			if (length <= sizeof(uuid_string_t)) {
419*19c3b8c2SApple OSS Distributions 				/* ensure caller's buffer is fully initialized: */
420*19c3b8c2SApple OSS Distributions 				bzero(uuid, sizeof(uuid_string_t));
421*19c3b8c2SApple OSS Distributions 				/* copy the content of uuid_data->getBytesNoCopy() into uuid */
422*19c3b8c2SApple OSS Distributions 				memcpy(uuid, uuid_data->getBytesNoCopy(), length);
423*19c3b8c2SApple OSS Distributions 				/* guarantee nul-termination: */
424*19c3b8c2SApple OSS Distributions 				uuid[sizeof(uuid_string_t) - 1] = '\0';
425*19c3b8c2SApple OSS Distributions 				result = true;
426*19c3b8c2SApple OSS Distributions 			} else {
427*19c3b8c2SApple OSS Distributions 				uuid = NULL;
428*19c3b8c2SApple OSS Distributions 			}
429*19c3b8c2SApple OSS Distributions 		}
430*19c3b8c2SApple OSS Distributions 		OSSafeReleaseNULL(entry);
431*19c3b8c2SApple OSS Distributions 	}
432*19c3b8c2SApple OSS Distributions 	return result;
433*19c3b8c2SApple OSS Distributions }
434*19c3b8c2SApple OSS Distributions 
435*19c3b8c2SApple OSS Distributions bool
IOGetApfsPrebootUUID(char * uuid)436*19c3b8c2SApple OSS Distributions IOGetApfsPrebootUUID(char *uuid)
437*19c3b8c2SApple OSS Distributions {
438*19c3b8c2SApple OSS Distributions 	IORegistryEntry *entry;
439*19c3b8c2SApple OSS Distributions 	OSData *uuid_data = NULL;
440*19c3b8c2SApple OSS Distributions 	bool result = false;
441*19c3b8c2SApple OSS Distributions 
442*19c3b8c2SApple OSS Distributions 	if ((entry = IORegistryEntry::fromPath("/chosen", gIODTPlane))) {
443*19c3b8c2SApple OSS Distributions 		uuid_data = (OSData *)entry->getProperty("apfs-preboot-uuid");
444*19c3b8c2SApple OSS Distributions 
445*19c3b8c2SApple OSS Distributions 		if (uuid_data) {
446*19c3b8c2SApple OSS Distributions 			unsigned int length = uuid_data->getLength();
447*19c3b8c2SApple OSS Distributions 			if (length <= sizeof(uuid_string_t)) {
448*19c3b8c2SApple OSS Distributions 				/* ensure caller's buffer is fully initialized: */
449*19c3b8c2SApple OSS Distributions 				bzero(uuid, sizeof(uuid_string_t));
450*19c3b8c2SApple OSS Distributions 				/* copy the content of uuid_data->getBytesNoCopy() into uuid */
451*19c3b8c2SApple OSS Distributions 				memcpy(uuid, uuid_data->getBytesNoCopy(), length);
452*19c3b8c2SApple OSS Distributions 				/* guarantee nul-termination: */
453*19c3b8c2SApple OSS Distributions 				uuid[sizeof(uuid_string_t) - 1] = '\0';
454*19c3b8c2SApple OSS Distributions 				result = true;
455*19c3b8c2SApple OSS Distributions 			} else {
456*19c3b8c2SApple OSS Distributions 				uuid = NULL;
457*19c3b8c2SApple OSS Distributions 			}
458*19c3b8c2SApple OSS Distributions 		}
459*19c3b8c2SApple OSS Distributions 		OSSafeReleaseNULL(entry);
460*19c3b8c2SApple OSS Distributions 	}
461*19c3b8c2SApple OSS Distributions 	return result;
462*19c3b8c2SApple OSS Distributions }
463*19c3b8c2SApple OSS Distributions 
464*19c3b8c2SApple OSS Distributions bool
IOGetAssociatedApfsVolgroupUUID(char * uuid)465*19c3b8c2SApple OSS Distributions IOGetAssociatedApfsVolgroupUUID(char *uuid)
466*19c3b8c2SApple OSS Distributions {
467*19c3b8c2SApple OSS Distributions 	IORegistryEntry *entry;
468*19c3b8c2SApple OSS Distributions 	OSData *uuid_data = NULL;
469*19c3b8c2SApple OSS Distributions 	bool result = false;
470*19c3b8c2SApple OSS Distributions 
471*19c3b8c2SApple OSS Distributions 	if ((entry = IORegistryEntry::fromPath("/chosen", gIODTPlane))) {
472*19c3b8c2SApple OSS Distributions 		uuid_data = (OSData *)entry->getProperty("associated-volume-group");
473*19c3b8c2SApple OSS Distributions 
474*19c3b8c2SApple OSS Distributions 		if (uuid_data) {
475*19c3b8c2SApple OSS Distributions 			unsigned int length = uuid_data->getLength();
476*19c3b8c2SApple OSS Distributions 
477*19c3b8c2SApple OSS Distributions 			if (length <= sizeof(uuid_string_t)) {
478*19c3b8c2SApple OSS Distributions 				/* ensure caller's buffer is fully initialized: */
479*19c3b8c2SApple OSS Distributions 				bzero(uuid, sizeof(uuid_string_t));
480*19c3b8c2SApple OSS Distributions 				/* copy the content of uuid_data->getBytesNoCopy() into uuid */
481*19c3b8c2SApple OSS Distributions 				memcpy(uuid, uuid_data->getBytesNoCopy(), length);
482*19c3b8c2SApple OSS Distributions 				/* guarantee nul-termination: */
483*19c3b8c2SApple OSS Distributions 				uuid[sizeof(uuid_string_t) - 1] = '\0';
484*19c3b8c2SApple OSS Distributions 				result = true;
485*19c3b8c2SApple OSS Distributions 			} else {
486*19c3b8c2SApple OSS Distributions 				uuid = NULL;
487*19c3b8c2SApple OSS Distributions 			}
488*19c3b8c2SApple OSS Distributions 		}
489*19c3b8c2SApple OSS Distributions 		OSSafeReleaseNULL(entry);
490*19c3b8c2SApple OSS Distributions 	}
491*19c3b8c2SApple OSS Distributions 	return result;
492*19c3b8c2SApple OSS Distributions }
493*19c3b8c2SApple OSS Distributions 
494*19c3b8c2SApple OSS Distributions bool
IOGetBootObjectsPath(char * path_prefix)495*19c3b8c2SApple OSS Distributions IOGetBootObjectsPath(char *path_prefix)
496*19c3b8c2SApple OSS Distributions {
497*19c3b8c2SApple OSS Distributions 	IORegistryEntry *entry;
498*19c3b8c2SApple OSS Distributions 	OSData *path_prefix_data = NULL;
499*19c3b8c2SApple OSS Distributions 	bool result = false;
500*19c3b8c2SApple OSS Distributions 
501*19c3b8c2SApple OSS Distributions 	if ((entry = IORegistryEntry::fromPath("/chosen", gIODTPlane))) {
502*19c3b8c2SApple OSS Distributions 		path_prefix_data = (OSData *)entry->getProperty("boot-objects-path");
503*19c3b8c2SApple OSS Distributions 
504*19c3b8c2SApple OSS Distributions 		if (path_prefix_data) {
505*19c3b8c2SApple OSS Distributions 			unsigned int length = path_prefix_data->getLength();
506*19c3b8c2SApple OSS Distributions 
507*19c3b8c2SApple OSS Distributions 			if (length <= MAXPATHLEN) {
508*19c3b8c2SApple OSS Distributions 				/* ensure caller's buffer is fully initialized: */
509*19c3b8c2SApple OSS Distributions 				bzero(path_prefix, MAXPATHLEN);
510*19c3b8c2SApple OSS Distributions 				/* copy the content of path_prefix_data->getBytesNoCopy() into path_prefix */
511*19c3b8c2SApple OSS Distributions 				memcpy(path_prefix, path_prefix_data->getBytesNoCopy(), length);
512*19c3b8c2SApple OSS Distributions 				/* guarantee nul-termination: */
513*19c3b8c2SApple OSS Distributions 				path_prefix[MAXPATHLEN - 1] = '\0';
514*19c3b8c2SApple OSS Distributions 				result = true;
515*19c3b8c2SApple OSS Distributions 			} else {
516*19c3b8c2SApple OSS Distributions 				path_prefix = NULL;
517*19c3b8c2SApple OSS Distributions 			}
518*19c3b8c2SApple OSS Distributions 		}
519*19c3b8c2SApple OSS Distributions 		OSSafeReleaseNULL(entry);
520*19c3b8c2SApple OSS Distributions 	}
521*19c3b8c2SApple OSS Distributions 	return result;
522*19c3b8c2SApple OSS Distributions }
523*19c3b8c2SApple OSS Distributions 
524*19c3b8c2SApple OSS Distributions 
525*19c3b8c2SApple OSS Distributions bool
IOGetBootManifestHash(char * hash_data,size_t * hash_data_size)526*19c3b8c2SApple OSS Distributions IOGetBootManifestHash(char *hash_data, size_t *hash_data_size)
527*19c3b8c2SApple OSS Distributions {
528*19c3b8c2SApple OSS Distributions 	IORegistryEntry *entry = NULL;
529*19c3b8c2SApple OSS Distributions 	OSData *manifest_hash_data = NULL;
530*19c3b8c2SApple OSS Distributions 	bool result = false;
531*19c3b8c2SApple OSS Distributions 
532*19c3b8c2SApple OSS Distributions 	if ((entry = IORegistryEntry::fromPath("/chosen", gIODTPlane))) {
533*19c3b8c2SApple OSS Distributions 		manifest_hash_data = (OSData *)entry->getProperty("boot-manifest-hash");
534*19c3b8c2SApple OSS Distributions 		if (manifest_hash_data) {
535*19c3b8c2SApple OSS Distributions 			unsigned int length = manifest_hash_data->getLength();
536*19c3b8c2SApple OSS Distributions 			/* hashed with SHA2-384 or SHA1, the boot manifest hash should be 48 Bytes or less */
537*19c3b8c2SApple OSS Distributions 			if ((length <= CCSHA384_OUTPUT_SIZE) && (*hash_data_size >= CCSHA384_OUTPUT_SIZE)) {
538*19c3b8c2SApple OSS Distributions 				/* ensure caller's buffer is fully initialized: */
539*19c3b8c2SApple OSS Distributions 				bzero(hash_data, CCSHA384_OUTPUT_SIZE);
540*19c3b8c2SApple OSS Distributions 				/* copy the content of manifest_hash_data->getBytesNoCopy() into hash_data */
541*19c3b8c2SApple OSS Distributions 				memcpy(hash_data, manifest_hash_data->getBytesNoCopy(), length);
542*19c3b8c2SApple OSS Distributions 				*hash_data_size = length;
543*19c3b8c2SApple OSS Distributions 				result = true;
544*19c3b8c2SApple OSS Distributions 			} else {
545*19c3b8c2SApple OSS Distributions 				hash_data = NULL;
546*19c3b8c2SApple OSS Distributions 				*hash_data_size = 0;
547*19c3b8c2SApple OSS Distributions 			}
548*19c3b8c2SApple OSS Distributions 		}
549*19c3b8c2SApple OSS Distributions 		OSSafeReleaseNULL(entry);
550*19c3b8c2SApple OSS Distributions 	}
551*19c3b8c2SApple OSS Distributions 
552*19c3b8c2SApple OSS Distributions 	return result;
553*19c3b8c2SApple OSS Distributions }
554*19c3b8c2SApple OSS Distributions 
555*19c3b8c2SApple OSS Distributions /*
556*19c3b8c2SApple OSS Distributions  * Set NVRAM to boot into the right flavor of Recovery,
557*19c3b8c2SApple OSS Distributions  * optionally passing a UUID of a volume that failed to boot.
558*19c3b8c2SApple OSS Distributions  * If `reboot` is true, reboot immediately.
559*19c3b8c2SApple OSS Distributions  *
560*19c3b8c2SApple OSS Distributions  * Returns true if `mode` was understood, false otherwise.
561*19c3b8c2SApple OSS Distributions  * (Does not return if `reboot` is true.)
562*19c3b8c2SApple OSS Distributions  */
563*19c3b8c2SApple OSS Distributions boolean_t
IOSetRecoveryBoot(bsd_bootfail_mode_t mode,uuid_t volume_uuid,boolean_t reboot)564*19c3b8c2SApple OSS Distributions IOSetRecoveryBoot(bsd_bootfail_mode_t mode, uuid_t volume_uuid, boolean_t reboot)
565*19c3b8c2SApple OSS Distributions {
566*19c3b8c2SApple OSS Distributions 	IODTNVRAM *nvram = NULL;
567*19c3b8c2SApple OSS Distributions 	const OSSymbol *boot_command_sym = NULL;
568*19c3b8c2SApple OSS Distributions 	OSString *boot_command_recover = NULL;
569*19c3b8c2SApple OSS Distributions 
570*19c3b8c2SApple OSS Distributions 	if (mode == BSD_BOOTFAIL_SEAL_BROKEN) {
571*19c3b8c2SApple OSS Distributions 		const char *boot_mode = "ssv-seal-broken";
572*19c3b8c2SApple OSS Distributions 		uuid_string_t volume_uuid_str;
573*19c3b8c2SApple OSS Distributions 
574*19c3b8c2SApple OSS Distributions 		// Set `recovery-broken-seal-uuid = <volume_uuid>`.
575*19c3b8c2SApple OSS Distributions 		if (volume_uuid) {
576*19c3b8c2SApple OSS Distributions 			uuid_unparse_upper(volume_uuid, volume_uuid_str);
577*19c3b8c2SApple OSS Distributions 
578*19c3b8c2SApple OSS Distributions 			if (!PEWriteNVRAMProperty(SYSTEM_NVRAM_PREFIX "recovery-broken-seal-uuid",
579*19c3b8c2SApple OSS Distributions 			    volume_uuid_str, sizeof(uuid_string_t))) {
580*19c3b8c2SApple OSS Distributions 				IOLog("Failed to write recovery-broken-seal-uuid to NVRAM.\n");
581*19c3b8c2SApple OSS Distributions 			}
582*19c3b8c2SApple OSS Distributions 		}
583*19c3b8c2SApple OSS Distributions 
584*19c3b8c2SApple OSS Distributions 		// Set `recovery-boot-mode = ssv-seal-broken`.
585*19c3b8c2SApple OSS Distributions 		if (!PEWriteNVRAMProperty(SYSTEM_NVRAM_PREFIX "recovery-boot-mode", boot_mode,
586*19c3b8c2SApple OSS Distributions 		    (const unsigned int) strlen(boot_mode))) {
587*19c3b8c2SApple OSS Distributions 			IOLog("Failed to write recovery-boot-mode to NVRAM.\n");
588*19c3b8c2SApple OSS Distributions 		}
589*19c3b8c2SApple OSS Distributions 	} else if (mode == BSD_BOOTFAIL_MEDIA_MISSING) {
590*19c3b8c2SApple OSS Distributions 		const char *boot_picker_reason = "missing-boot-media";
591*19c3b8c2SApple OSS Distributions 
592*19c3b8c2SApple OSS Distributions 		// Set `boot-picker-bringup-reason = missing-boot-media`.
593*19c3b8c2SApple OSS Distributions 		if (!PEWriteNVRAMProperty(SYSTEM_NVRAM_PREFIX "boot-picker-bringup-reason",
594*19c3b8c2SApple OSS Distributions 		    boot_picker_reason, (const unsigned int) strlen(boot_picker_reason))) {
595*19c3b8c2SApple OSS Distributions 			IOLog("Failed to write boot-picker-bringup-reason to NVRAM.\n");
596*19c3b8c2SApple OSS Distributions 		}
597*19c3b8c2SApple OSS Distributions 
598*19c3b8c2SApple OSS Distributions 		// Set `boot-command = recover-system`.
599*19c3b8c2SApple OSS Distributions 
600*19c3b8c2SApple OSS Distributions 		// Construct an OSSymbol and an OSString to be the (key, value) pair
601*19c3b8c2SApple OSS Distributions 		// we write to NVRAM. Unfortunately, since our value must be an OSString
602*19c3b8c2SApple OSS Distributions 		// instead of an OSData, we cannot use PEWriteNVRAMProperty() here.
603*19c3b8c2SApple OSS Distributions 		boot_command_sym = OSSymbol::withCStringNoCopy(SYSTEM_NVRAM_PREFIX "boot-command");
604*19c3b8c2SApple OSS Distributions 		boot_command_recover = OSString::withCStringNoCopy("recover-system");
605*19c3b8c2SApple OSS Distributions 		if (boot_command_sym == NULL || boot_command_recover == NULL) {
606*19c3b8c2SApple OSS Distributions 			IOLog("Failed to create boot-command strings.\n");
607*19c3b8c2SApple OSS Distributions 			goto do_reboot;
608*19c3b8c2SApple OSS Distributions 		}
609*19c3b8c2SApple OSS Distributions 
610*19c3b8c2SApple OSS Distributions 		// Wait for NVRAM to be readable...
611*19c3b8c2SApple OSS Distributions 		nvram = OSDynamicCast(IODTNVRAM, IOService::waitForService(
612*19c3b8c2SApple OSS Distributions 			    IOService::serviceMatching("IODTNVRAM")));
613*19c3b8c2SApple OSS Distributions 		if (nvram == NULL) {
614*19c3b8c2SApple OSS Distributions 			IOLog("Failed to acquire IODTNVRAM object.\n");
615*19c3b8c2SApple OSS Distributions 			goto do_reboot;
616*19c3b8c2SApple OSS Distributions 		}
617*19c3b8c2SApple OSS Distributions 
618*19c3b8c2SApple OSS Distributions 		// Wait for NVRAM to be writable...
619*19c3b8c2SApple OSS Distributions 		if (!IOServiceWaitForMatchingResource("IONVRAM", UINT64_MAX)) {
620*19c3b8c2SApple OSS Distributions 			IOLog("Failed to wait for IONVRAM service.\n");
621*19c3b8c2SApple OSS Distributions 			// attempt the work anyway...
622*19c3b8c2SApple OSS Distributions 		}
623*19c3b8c2SApple OSS Distributions 
624*19c3b8c2SApple OSS Distributions 		// Write the new boot-command to NVRAM, and sync if successful.
625*19c3b8c2SApple OSS Distributions 		if (!nvram->setProperty(boot_command_sym, boot_command_recover)) {
626*19c3b8c2SApple OSS Distributions 			IOLog("Failed to save new boot-command to NVRAM.\n");
627*19c3b8c2SApple OSS Distributions 		} else {
628*19c3b8c2SApple OSS Distributions 			nvram->sync();
629*19c3b8c2SApple OSS Distributions 		}
630*19c3b8c2SApple OSS Distributions 	} else {
631*19c3b8c2SApple OSS Distributions 		IOLog("Unknown mode: %d\n", mode);
632*19c3b8c2SApple OSS Distributions 		return false;
633*19c3b8c2SApple OSS Distributions 	}
634*19c3b8c2SApple OSS Distributions 
635*19c3b8c2SApple OSS Distributions 	// Clean up and reboot!
636*19c3b8c2SApple OSS Distributions do_reboot:
637*19c3b8c2SApple OSS Distributions 	if (boot_command_recover != NULL) {
638*19c3b8c2SApple OSS Distributions 		boot_command_recover->release();
639*19c3b8c2SApple OSS Distributions 	}
640*19c3b8c2SApple OSS Distributions 
641*19c3b8c2SApple OSS Distributions 	if (boot_command_sym != NULL) {
642*19c3b8c2SApple OSS Distributions 		boot_command_sym->release();
643*19c3b8c2SApple OSS Distributions 	}
644*19c3b8c2SApple OSS Distributions 
645*19c3b8c2SApple OSS Distributions 	if (reboot) {
646*19c3b8c2SApple OSS Distributions 		IOLog("\nAbout to reboot into Recovery!\n");
647*19c3b8c2SApple OSS Distributions 		(void)PEHaltRestart(kPERestartCPU);
648*19c3b8c2SApple OSS Distributions 	}
649*19c3b8c2SApple OSS Distributions 
650*19c3b8c2SApple OSS Distributions 	return true;
651*19c3b8c2SApple OSS Distributions }
652*19c3b8c2SApple OSS Distributions 
653*19c3b8c2SApple OSS Distributions kern_return_t
IOFindBSDRoot(char * rootName,unsigned int rootNameSize,dev_t * root,u_int32_t * oflags)654*19c3b8c2SApple OSS Distributions IOFindBSDRoot( char * rootName, unsigned int rootNameSize,
655*19c3b8c2SApple OSS Distributions     dev_t * root, u_int32_t * oflags )
656*19c3b8c2SApple OSS Distributions {
657*19c3b8c2SApple OSS Distributions 	mach_timespec_t     t;
658*19c3b8c2SApple OSS Distributions 	IOService *         service;
659*19c3b8c2SApple OSS Distributions 	IORegistryEntry *   regEntry;
660*19c3b8c2SApple OSS Distributions 	OSDictionary *      matching = NULL;
661*19c3b8c2SApple OSS Distributions 	OSString *          iostr;
662*19c3b8c2SApple OSS Distributions 	OSNumber *          off;
663*19c3b8c2SApple OSS Distributions 	OSData *            data = NULL;
664*19c3b8c2SApple OSS Distributions 
665*19c3b8c2SApple OSS Distributions 	UInt32              flags = 0;
666*19c3b8c2SApple OSS Distributions 	int                 mnr, mjr;
667*19c3b8c2SApple OSS Distributions 	const char *        mediaProperty = NULL;
668*19c3b8c2SApple OSS Distributions 	char *              rdBootVar;
669*19c3b8c2SApple OSS Distributions 	OSDataAllocation<char> str;
670*19c3b8c2SApple OSS Distributions 	const char *        look = NULL;
671*19c3b8c2SApple OSS Distributions 	int                 len;
672*19c3b8c2SApple OSS Distributions 	bool                debugInfoPrintedOnce = false;
673*19c3b8c2SApple OSS Distributions 	bool                needNetworkKexts = false;
674*19c3b8c2SApple OSS Distributions 	const char *        uuidStr = NULL;
675*19c3b8c2SApple OSS Distributions 
676*19c3b8c2SApple OSS Distributions 	static int          mountAttempts = 0;
677*19c3b8c2SApple OSS Distributions 
678*19c3b8c2SApple OSS Distributions 	int xchar, dchar;
679*19c3b8c2SApple OSS Distributions 
680*19c3b8c2SApple OSS Distributions 	// stall here for anyone matching on the IOBSD resource to finish (filesystems)
681*19c3b8c2SApple OSS Distributions 	matching = IOService::serviceMatching(gIOResourcesKey);
682*19c3b8c2SApple OSS Distributions 	assert(matching);
683*19c3b8c2SApple OSS Distributions 	matching->setObject(gIOResourceMatchedKey, gIOBSDKey);
684*19c3b8c2SApple OSS Distributions 
685*19c3b8c2SApple OSS Distributions 	if ((service = IOService::waitForMatchingService(matching, 30ULL * kSecondScale))) {
686*19c3b8c2SApple OSS Distributions 		OSSafeReleaseNULL(service);
687*19c3b8c2SApple OSS Distributions 	} else {
688*19c3b8c2SApple OSS Distributions 		IOLog("!BSD\n");
689*19c3b8c2SApple OSS Distributions 	}
690*19c3b8c2SApple OSS Distributions 	matching->release();
691*19c3b8c2SApple OSS Distributions 	matching = NULL;
692*19c3b8c2SApple OSS Distributions 
693*19c3b8c2SApple OSS Distributions 	if (mountAttempts++) {
694*19c3b8c2SApple OSS Distributions 		IOLog("mount(%d) failed\n", mountAttempts);
695*19c3b8c2SApple OSS Distributions 		IOSleep( 5 * 1000 );
696*19c3b8c2SApple OSS Distributions 	}
697*19c3b8c2SApple OSS Distributions 
698*19c3b8c2SApple OSS Distributions 	str = OSDataAllocation<char>( kMaxPathBuf + kMaxBootVar, OSAllocateMemory );
699*19c3b8c2SApple OSS Distributions 	if (!str) {
700*19c3b8c2SApple OSS Distributions 		return kIOReturnNoMemory;
701*19c3b8c2SApple OSS Distributions 	}
702*19c3b8c2SApple OSS Distributions 	rdBootVar = str.data() + kMaxPathBuf;
703*19c3b8c2SApple OSS Distributions 
704*19c3b8c2SApple OSS Distributions 	if (!PE_parse_boot_argn("rd", rdBootVar, kMaxBootVar )
705*19c3b8c2SApple OSS Distributions 	    && !PE_parse_boot_argn("rootdev", rdBootVar, kMaxBootVar )) {
706*19c3b8c2SApple OSS Distributions 		rdBootVar[0] = 0;
707*19c3b8c2SApple OSS Distributions 	}
708*19c3b8c2SApple OSS Distributions 
709*19c3b8c2SApple OSS Distributions 	if ((regEntry = IORegistryEntry::fromPath( "/chosen", gIODTPlane ))) {
710*19c3b8c2SApple OSS Distributions 		do {
711*19c3b8c2SApple OSS Distributions 			di_root_ramfile(regEntry);
712*19c3b8c2SApple OSS Distributions 			OSObject* unserializedContainer = NULL;
713*19c3b8c2SApple OSS Distributions 			data = OSDynamicCast(OSData, regEntry->getProperty( "root-matching" ));
714*19c3b8c2SApple OSS Distributions 			if (data) {
715*19c3b8c2SApple OSS Distributions 				unserializedContainer = OSUnserializeXML((char *)data->getBytesNoCopy());
716*19c3b8c2SApple OSS Distributions 				matching = OSDynamicCast(OSDictionary, unserializedContainer);
717*19c3b8c2SApple OSS Distributions 				if (matching) {
718*19c3b8c2SApple OSS Distributions 					continue;
719*19c3b8c2SApple OSS Distributions 				}
720*19c3b8c2SApple OSS Distributions 			}
721*19c3b8c2SApple OSS Distributions 			OSSafeReleaseNULL(unserializedContainer);
722*19c3b8c2SApple OSS Distributions 
723*19c3b8c2SApple OSS Distributions 			data = (OSData *) regEntry->getProperty( "boot-uuid" );
724*19c3b8c2SApple OSS Distributions 			if (data) {
725*19c3b8c2SApple OSS Distributions 				uuidStr = (const char*)data->getBytesNoCopy();
726*19c3b8c2SApple OSS Distributions 				OSString *uuidString = OSString::withCString( uuidStr );
727*19c3b8c2SApple OSS Distributions 
728*19c3b8c2SApple OSS Distributions 				// match the boot-args boot-uuid processing below
729*19c3b8c2SApple OSS Distributions 				if (uuidString) {
730*19c3b8c2SApple OSS Distributions 					IOLog("rooting via boot-uuid from /chosen: %s\n", uuidStr);
731*19c3b8c2SApple OSS Distributions 					IOService::publishResource( "boot-uuid", uuidString );
732*19c3b8c2SApple OSS Distributions 					uuidString->release();
733*19c3b8c2SApple OSS Distributions 					matching = IOUUIDMatching();
734*19c3b8c2SApple OSS Distributions 					mediaProperty = "boot-uuid-media";
735*19c3b8c2SApple OSS Distributions 					continue;
736*19c3b8c2SApple OSS Distributions 				} else {
737*19c3b8c2SApple OSS Distributions 					uuidStr = NULL;
738*19c3b8c2SApple OSS Distributions 				}
739*19c3b8c2SApple OSS Distributions 			}
740*19c3b8c2SApple OSS Distributions 		} while (false);
741*19c3b8c2SApple OSS Distributions 		OSSafeReleaseNULL(regEntry);
742*19c3b8c2SApple OSS Distributions 	}
743*19c3b8c2SApple OSS Distributions 
744*19c3b8c2SApple OSS Distributions //
745*19c3b8c2SApple OSS Distributions //	See if we have a RAMDisk property in /chosen/memory-map.  If so, make it into a device.
746*19c3b8c2SApple OSS Distributions //	It will become /dev/mdx, where x is 0-f.
747*19c3b8c2SApple OSS Distributions //
748*19c3b8c2SApple OSS Distributions 
749*19c3b8c2SApple OSS Distributions 	if (!didRam) {                                                                                           /* Have we already build this ram disk? */
750*19c3b8c2SApple OSS Distributions 		didRam = 1;                                                                                             /* Remember we did this */
751*19c3b8c2SApple OSS Distributions 		if ((regEntry = IORegistryEntry::fromPath( "/chosen/memory-map", gIODTPlane ))) {        /* Find the map node */
752*19c3b8c2SApple OSS Distributions 			data = (OSData *)regEntry->getProperty("RAMDisk");      /* Find the ram disk, if there */
753*19c3b8c2SApple OSS Distributions 			if (data) {                                                                                      /* We found one */
754*19c3b8c2SApple OSS Distributions 				uintptr_t *ramdParms;
755*19c3b8c2SApple OSS Distributions 				ramdParms = (uintptr_t *)data->getBytesNoCopy();        /* Point to the ram disk base and size */
756*19c3b8c2SApple OSS Distributions #if __LP64__
757*19c3b8c2SApple OSS Distributions #define MAX_PHYS_RAM    (((uint64_t)UINT_MAX) << 12)
758*19c3b8c2SApple OSS Distributions 				if (ramdParms[1] > MAX_PHYS_RAM) {
759*19c3b8c2SApple OSS Distributions 					panic("ramdisk params");
760*19c3b8c2SApple OSS Distributions 				}
761*19c3b8c2SApple OSS Distributions #endif /* __LP64__ */
762*19c3b8c2SApple OSS Distributions 				(void)mdevadd(-1, ml_static_ptovirt(ramdParms[0]) >> 12, (unsigned int) (ramdParms[1] >> 12), 0);        /* Initialize it and pass back the device number */
763*19c3b8c2SApple OSS Distributions 			}
764*19c3b8c2SApple OSS Distributions 			regEntry->release();                                                            /* Toss the entry */
765*19c3b8c2SApple OSS Distributions 		}
766*19c3b8c2SApple OSS Distributions 	}
767*19c3b8c2SApple OSS Distributions 
768*19c3b8c2SApple OSS Distributions //
769*19c3b8c2SApple OSS Distributions //	Now check if we are trying to root on a memory device
770*19c3b8c2SApple OSS Distributions //
771*19c3b8c2SApple OSS Distributions 
772*19c3b8c2SApple OSS Distributions 	if ((rdBootVar[0] == 'm') && (rdBootVar[1] == 'd') && (rdBootVar[3] == 0)) {
773*19c3b8c2SApple OSS Distributions 		dchar = xchar = rdBootVar[2];                                                   /* Get the actual device */
774*19c3b8c2SApple OSS Distributions 		if ((xchar >= '0') && (xchar <= '9')) {
775*19c3b8c2SApple OSS Distributions 			xchar = xchar - '0';                                    /* If digit, convert */
776*19c3b8c2SApple OSS Distributions 		} else {
777*19c3b8c2SApple OSS Distributions 			xchar = xchar & ~' ';                                                           /* Fold to upper case */
778*19c3b8c2SApple OSS Distributions 			if ((xchar >= 'A') && (xchar <= 'F')) {                          /* Is this a valid digit? */
779*19c3b8c2SApple OSS Distributions 				xchar = (xchar & 0xF) + 9;                                              /* Convert the hex digit */
780*19c3b8c2SApple OSS Distributions 				dchar = dchar | ' ';                                                    /* Fold to lower case */
781*19c3b8c2SApple OSS Distributions 			} else {
782*19c3b8c2SApple OSS Distributions 				xchar = -1;                                                                     /* Show bogus */
783*19c3b8c2SApple OSS Distributions 			}
784*19c3b8c2SApple OSS Distributions 		}
785*19c3b8c2SApple OSS Distributions 		if (xchar >= 0) {                                                                                /* Do we have a valid memory device name? */
786*19c3b8c2SApple OSS Distributions 			OSSafeReleaseNULL(matching);
787*19c3b8c2SApple OSS Distributions 			*root = mdevlookup(xchar);                                                      /* Find the device number */
788*19c3b8c2SApple OSS Distributions 			if (*root >= 0) {                                                                        /* Did we find one? */
789*19c3b8c2SApple OSS Distributions 				rootName[0] = 'm';                                                              /* Build root name */
790*19c3b8c2SApple OSS Distributions 				rootName[1] = 'd';                                                              /* Build root name */
791*19c3b8c2SApple OSS Distributions 				rootName[2] = (char) dchar;                                                     /* Build root name */
792*19c3b8c2SApple OSS Distributions 				rootName[3] = 0;                                                                /* Build root name */
793*19c3b8c2SApple OSS Distributions 				IOLog("BSD root: %s, major %d, minor %d\n", rootName, major(*root), minor(*root));
794*19c3b8c2SApple OSS Distributions 				*oflags = 0;                                                                    /* Show that this is not network */
795*19c3b8c2SApple OSS Distributions 
796*19c3b8c2SApple OSS Distributions #if CONFIG_KDP_INTERACTIVE_DEBUGGING
797*19c3b8c2SApple OSS Distributions 				/* retrieve final ramdisk range and initialize KDP variables */
798*19c3b8c2SApple OSS Distributions 				if (mdevgetrange(xchar, &kdp_core_ramdisk_addr, &kdp_core_ramdisk_size) != 0) {
799*19c3b8c2SApple OSS Distributions 					IOLog("Unable to retrieve range for root memory device %d\n", xchar);
800*19c3b8c2SApple OSS Distributions 					kdp_core_ramdisk_addr = 0;
801*19c3b8c2SApple OSS Distributions 					kdp_core_ramdisk_size = 0;
802*19c3b8c2SApple OSS Distributions 				}
803*19c3b8c2SApple OSS Distributions #endif
804*19c3b8c2SApple OSS Distributions 
805*19c3b8c2SApple OSS Distributions 				goto iofrootx;                                                                  /* Join common exit... */
806*19c3b8c2SApple OSS Distributions 			}
807*19c3b8c2SApple OSS Distributions 			panic("IOFindBSDRoot: specified root memory device, %s, has not been configured", rdBootVar); /* Not there */
808*19c3b8c2SApple OSS Distributions 		}
809*19c3b8c2SApple OSS Distributions 	}
810*19c3b8c2SApple OSS Distributions 
811*19c3b8c2SApple OSS Distributions 	if ((!matching) && rdBootVar[0]) {
812*19c3b8c2SApple OSS Distributions 		// by BSD name
813*19c3b8c2SApple OSS Distributions 		look = rdBootVar;
814*19c3b8c2SApple OSS Distributions 		if (look[0] == '*') {
815*19c3b8c2SApple OSS Distributions 			look++;
816*19c3b8c2SApple OSS Distributions 		}
817*19c3b8c2SApple OSS Distributions 
818*19c3b8c2SApple OSS Distributions 		if (strncmp( look, "en", strlen( "en" )) == 0) {
819*19c3b8c2SApple OSS Distributions 			matching = IONetworkNamePrefixMatching( "en" );
820*19c3b8c2SApple OSS Distributions 			needNetworkKexts = true;
821*19c3b8c2SApple OSS Distributions 		} else if (strncmp( look, "uuid", strlen( "uuid" )) == 0) {
822*19c3b8c2SApple OSS Distributions 			OSDataAllocation<char> uuid( kMaxBootVar, OSAllocateMemory );
823*19c3b8c2SApple OSS Distributions 
824*19c3b8c2SApple OSS Distributions 			if (uuid) {
825*19c3b8c2SApple OSS Distributions 				OSString *uuidString;
826*19c3b8c2SApple OSS Distributions 
827*19c3b8c2SApple OSS Distributions 				if (!PE_parse_boot_argn( "boot-uuid", uuid.data(), kMaxBootVar )) {
828*19c3b8c2SApple OSS Distributions 					panic( "rd=uuid but no boot-uuid=<value> specified" );
829*19c3b8c2SApple OSS Distributions 				}
830*19c3b8c2SApple OSS Distributions 				uuidString = OSString::withCString(uuid.data());
831*19c3b8c2SApple OSS Distributions 				if (uuidString) {
832*19c3b8c2SApple OSS Distributions 					IOService::publishResource( "boot-uuid", uuidString );
833*19c3b8c2SApple OSS Distributions 					uuidString->release();
834*19c3b8c2SApple OSS Distributions 					IOLog("\nWaiting for boot volume with UUID %s\n", uuid.data());
835*19c3b8c2SApple OSS Distributions 					matching = IOUUIDMatching();
836*19c3b8c2SApple OSS Distributions 					mediaProperty = "boot-uuid-media";
837*19c3b8c2SApple OSS Distributions 				}
838*19c3b8c2SApple OSS Distributions 			}
839*19c3b8c2SApple OSS Distributions 		} else {
840*19c3b8c2SApple OSS Distributions 			matching = IOBSDNameMatching( look );
841*19c3b8c2SApple OSS Distributions 		}
842*19c3b8c2SApple OSS Distributions 	}
843*19c3b8c2SApple OSS Distributions 
844*19c3b8c2SApple OSS Distributions 	if (!matching) {
845*19c3b8c2SApple OSS Distributions 		OSString * astring;
846*19c3b8c2SApple OSS Distributions 		// Match any HFS media
847*19c3b8c2SApple OSS Distributions 
848*19c3b8c2SApple OSS Distributions 		matching = IOService::serviceMatching( "IOMedia" );
849*19c3b8c2SApple OSS Distributions 		assert(matching);
850*19c3b8c2SApple OSS Distributions 		astring = OSString::withCStringNoCopy("Apple_HFS");
851*19c3b8c2SApple OSS Distributions 		if (astring) {
852*19c3b8c2SApple OSS Distributions 			matching->setObject("Content", astring);
853*19c3b8c2SApple OSS Distributions 			astring->release();
854*19c3b8c2SApple OSS Distributions 		}
855*19c3b8c2SApple OSS Distributions 	}
856*19c3b8c2SApple OSS Distributions 
857*19c3b8c2SApple OSS Distributions 	if (gIOKitDebug & kIOWaitQuietBeforeRoot) {
858*19c3b8c2SApple OSS Distributions 		IOLog( "Waiting for matching to complete\n" );
859*19c3b8c2SApple OSS Distributions 		IOService::getPlatform()->waitQuiet();
860*19c3b8c2SApple OSS Distributions 	}
861*19c3b8c2SApple OSS Distributions 
862*19c3b8c2SApple OSS Distributions 	if (matching) {
863*19c3b8c2SApple OSS Distributions 		OSSerialize * s = OSSerialize::withCapacity( 5 );
864*19c3b8c2SApple OSS Distributions 
865*19c3b8c2SApple OSS Distributions 		if (matching->serialize( s )) {
866*19c3b8c2SApple OSS Distributions 			IOLog( "Waiting on %s\n", s->text());
867*19c3b8c2SApple OSS Distributions 		}
868*19c3b8c2SApple OSS Distributions 		s->release();
869*19c3b8c2SApple OSS Distributions 	}
870*19c3b8c2SApple OSS Distributions 
871*19c3b8c2SApple OSS Distributions 	char namep[8];
872*19c3b8c2SApple OSS Distributions 	if (needNetworkKexts
873*19c3b8c2SApple OSS Distributions 	    || PE_parse_boot_argn("-s", namep, sizeof(namep))) {
874*19c3b8c2SApple OSS Distributions 		IOService::startDeferredMatches();
875*19c3b8c2SApple OSS Distributions 	}
876*19c3b8c2SApple OSS Distributions 
877*19c3b8c2SApple OSS Distributions 	do {
878*19c3b8c2SApple OSS Distributions 		t.tv_sec = ROOTDEVICETIMEOUT;
879*19c3b8c2SApple OSS Distributions 		t.tv_nsec = 0;
880*19c3b8c2SApple OSS Distributions 		matching->retain();
881*19c3b8c2SApple OSS Distributions 		service = IOService::waitForService( matching, &t );
882*19c3b8c2SApple OSS Distributions 		if ((!service) || (mountAttempts == 10)) {
883*19c3b8c2SApple OSS Distributions #if !XNU_TARGET_OS_OSX || !defined(__arm64__)
884*19c3b8c2SApple OSS Distributions 			PE_display_icon( 0, "noroot");
885*19c3b8c2SApple OSS Distributions 			IOLog( "Still waiting for root device\n" );
886*19c3b8c2SApple OSS Distributions #endif
887*19c3b8c2SApple OSS Distributions 
888*19c3b8c2SApple OSS Distributions 			if (!debugInfoPrintedOnce) {
889*19c3b8c2SApple OSS Distributions 				debugInfoPrintedOnce = true;
890*19c3b8c2SApple OSS Distributions 				if (gIOKitDebug & kIOLogDTree) {
891*19c3b8c2SApple OSS Distributions 					IOLog("\nDT plane:\n");
892*19c3b8c2SApple OSS Distributions 					IOPrintPlane( gIODTPlane );
893*19c3b8c2SApple OSS Distributions 				}
894*19c3b8c2SApple OSS Distributions 				if (gIOKitDebug & kIOLogServiceTree) {
895*19c3b8c2SApple OSS Distributions 					IOLog("\nService plane:\n");
896*19c3b8c2SApple OSS Distributions 					IOPrintPlane( gIOServicePlane );
897*19c3b8c2SApple OSS Distributions 				}
898*19c3b8c2SApple OSS Distributions 				if (gIOKitDebug & kIOLogMemory) {
899*19c3b8c2SApple OSS Distributions 					IOPrintMemory();
900*19c3b8c2SApple OSS Distributions 				}
901*19c3b8c2SApple OSS Distributions 			}
902*19c3b8c2SApple OSS Distributions 
903*19c3b8c2SApple OSS Distributions #if XNU_TARGET_OS_OSX && defined(__arm64__)
904*19c3b8c2SApple OSS Distributions 			// The disk isn't found - have the user pick from System Recovery.
905*19c3b8c2SApple OSS Distributions 			(void)IOSetRecoveryBoot(BSD_BOOTFAIL_MEDIA_MISSING, NULL, true);
906*19c3b8c2SApple OSS Distributions #elif XNU_TARGET_OS_IOS
907*19c3b8c2SApple OSS Distributions 			panic("Failed to mount root device");
908*19c3b8c2SApple OSS Distributions #endif
909*19c3b8c2SApple OSS Distributions 		}
910*19c3b8c2SApple OSS Distributions 	} while (!service);
911*19c3b8c2SApple OSS Distributions 
912*19c3b8c2SApple OSS Distributions 	OSSafeReleaseNULL(matching);
913*19c3b8c2SApple OSS Distributions 
914*19c3b8c2SApple OSS Distributions 	if (service && mediaProperty) {
915*19c3b8c2SApple OSS Distributions 		service = (IOService *)service->getProperty(mediaProperty);
916*19c3b8c2SApple OSS Distributions 	}
917*19c3b8c2SApple OSS Distributions 
918*19c3b8c2SApple OSS Distributions 	mjr = 0;
919*19c3b8c2SApple OSS Distributions 	mnr = 0;
920*19c3b8c2SApple OSS Distributions 
921*19c3b8c2SApple OSS Distributions 	// If the IOService we matched to is a subclass of IONetworkInterface,
922*19c3b8c2SApple OSS Distributions 	// then make sure it has been registered with BSD and has a BSD name
923*19c3b8c2SApple OSS Distributions 	// assigned.
924*19c3b8c2SApple OSS Distributions 
925*19c3b8c2SApple OSS Distributions 	if (service
926*19c3b8c2SApple OSS Distributions 	    && service->metaCast( "IONetworkInterface" )
927*19c3b8c2SApple OSS Distributions 	    && !IORegisterNetworkInterface( service )) {
928*19c3b8c2SApple OSS Distributions 		service = NULL;
929*19c3b8c2SApple OSS Distributions 	}
930*19c3b8c2SApple OSS Distributions 
931*19c3b8c2SApple OSS Distributions 	if (service) {
932*19c3b8c2SApple OSS Distributions 		len = kMaxPathBuf;
933*19c3b8c2SApple OSS Distributions 		service->getPath( str.data(), &len, gIOServicePlane );
934*19c3b8c2SApple OSS Distributions 		IOLog("Got boot device = %s\n", str.data());
935*19c3b8c2SApple OSS Distributions 
936*19c3b8c2SApple OSS Distributions 		iostr = (OSString *) service->getProperty( kIOBSDNameKey );
937*19c3b8c2SApple OSS Distributions 		if (iostr) {
938*19c3b8c2SApple OSS Distributions 			strlcpy( rootName, iostr->getCStringNoCopy(), rootNameSize );
939*19c3b8c2SApple OSS Distributions 		}
940*19c3b8c2SApple OSS Distributions 		off = (OSNumber *) service->getProperty( kIOBSDMajorKey );
941*19c3b8c2SApple OSS Distributions 		if (off) {
942*19c3b8c2SApple OSS Distributions 			mjr = off->unsigned32BitValue();
943*19c3b8c2SApple OSS Distributions 		}
944*19c3b8c2SApple OSS Distributions 		off = (OSNumber *) service->getProperty( kIOBSDMinorKey );
945*19c3b8c2SApple OSS Distributions 		if (off) {
946*19c3b8c2SApple OSS Distributions 			mnr = off->unsigned32BitValue();
947*19c3b8c2SApple OSS Distributions 		}
948*19c3b8c2SApple OSS Distributions 
949*19c3b8c2SApple OSS Distributions 		if (service->metaCast( "IONetworkInterface" )) {
950*19c3b8c2SApple OSS Distributions 			flags |= 1;
951*19c3b8c2SApple OSS Distributions 		}
952*19c3b8c2SApple OSS Distributions 	} else {
953*19c3b8c2SApple OSS Distributions 		IOLog( "Wait for root failed\n" );
954*19c3b8c2SApple OSS Distributions 		strlcpy( rootName, "en0", rootNameSize );
955*19c3b8c2SApple OSS Distributions 		flags |= 1;
956*19c3b8c2SApple OSS Distributions 	}
957*19c3b8c2SApple OSS Distributions 
958*19c3b8c2SApple OSS Distributions 	IOLog( "BSD root: %s", rootName );
959*19c3b8c2SApple OSS Distributions 	if (mjr) {
960*19c3b8c2SApple OSS Distributions 		IOLog(", major %d, minor %d\n", mjr, mnr );
961*19c3b8c2SApple OSS Distributions 	} else {
962*19c3b8c2SApple OSS Distributions 		IOLog("\n");
963*19c3b8c2SApple OSS Distributions 	}
964*19c3b8c2SApple OSS Distributions 
965*19c3b8c2SApple OSS Distributions 	*root = makedev( mjr, mnr );
966*19c3b8c2SApple OSS Distributions 	*oflags = flags;
967*19c3b8c2SApple OSS Distributions 
968*19c3b8c2SApple OSS Distributions iofrootx:
969*19c3b8c2SApple OSS Distributions 
970*19c3b8c2SApple OSS Distributions 	IOService::setRootMedia(service);
971*19c3b8c2SApple OSS Distributions 
972*19c3b8c2SApple OSS Distributions 	if ((gIOKitDebug & (kIOLogDTree | kIOLogServiceTree | kIOLogMemory)) && !debugInfoPrintedOnce) {
973*19c3b8c2SApple OSS Distributions 		IOService::getPlatform()->waitQuiet();
974*19c3b8c2SApple OSS Distributions 		if (gIOKitDebug & kIOLogDTree) {
975*19c3b8c2SApple OSS Distributions 			IOLog("\nDT plane:\n");
976*19c3b8c2SApple OSS Distributions 			IOPrintPlane( gIODTPlane );
977*19c3b8c2SApple OSS Distributions 		}
978*19c3b8c2SApple OSS Distributions 		if (gIOKitDebug & kIOLogServiceTree) {
979*19c3b8c2SApple OSS Distributions 			IOLog("\nService plane:\n");
980*19c3b8c2SApple OSS Distributions 			IOPrintPlane( gIOServicePlane );
981*19c3b8c2SApple OSS Distributions 		}
982*19c3b8c2SApple OSS Distributions 		if (gIOKitDebug & kIOLogMemory) {
983*19c3b8c2SApple OSS Distributions 			IOPrintMemory();
984*19c3b8c2SApple OSS Distributions 		}
985*19c3b8c2SApple OSS Distributions 	}
986*19c3b8c2SApple OSS Distributions 
987*19c3b8c2SApple OSS Distributions 	return kIOReturnSuccess;
988*19c3b8c2SApple OSS Distributions }
989*19c3b8c2SApple OSS Distributions 
990*19c3b8c2SApple OSS Distributions void
IOSetImageBoot(void)991*19c3b8c2SApple OSS Distributions IOSetImageBoot(void)
992*19c3b8c2SApple OSS Distributions {
993*19c3b8c2SApple OSS Distributions 	// this will unhide all IOMedia, without waiting for kernelmanagement to start
994*19c3b8c2SApple OSS Distributions 	IOService::setRootMedia(NULL);
995*19c3b8c2SApple OSS Distributions }
996*19c3b8c2SApple OSS Distributions 
997*19c3b8c2SApple OSS Distributions bool
IORamDiskBSDRoot(void)998*19c3b8c2SApple OSS Distributions IORamDiskBSDRoot(void)
999*19c3b8c2SApple OSS Distributions {
1000*19c3b8c2SApple OSS Distributions 	char rdBootVar[kMaxBootVar];
1001*19c3b8c2SApple OSS Distributions 	if (PE_parse_boot_argn("rd", rdBootVar, kMaxBootVar )
1002*19c3b8c2SApple OSS Distributions 	    || PE_parse_boot_argn("rootdev", rdBootVar, kMaxBootVar )) {
1003*19c3b8c2SApple OSS Distributions 		if ((rdBootVar[0] == 'm') && (rdBootVar[1] == 'd') && (rdBootVar[3] == 0)) {
1004*19c3b8c2SApple OSS Distributions 			return true;
1005*19c3b8c2SApple OSS Distributions 		}
1006*19c3b8c2SApple OSS Distributions 	}
1007*19c3b8c2SApple OSS Distributions 	return false;
1008*19c3b8c2SApple OSS Distributions }
1009*19c3b8c2SApple OSS Distributions 
1010*19c3b8c2SApple OSS Distributions void
IOSecureBSDRoot(const char * rootName)1011*19c3b8c2SApple OSS Distributions IOSecureBSDRoot(const char * rootName)
1012*19c3b8c2SApple OSS Distributions {
1013*19c3b8c2SApple OSS Distributions #if CONFIG_SECURE_BSD_ROOT
1014*19c3b8c2SApple OSS Distributions 	IOReturn         result;
1015*19c3b8c2SApple OSS Distributions 	IOPlatformExpert *pe;
1016*19c3b8c2SApple OSS Distributions 	OSDictionary     *matching;
1017*19c3b8c2SApple OSS Distributions 	const OSSymbol   *functionName = OSSymbol::withCStringNoCopy("SecureRootName");
1018*19c3b8c2SApple OSS Distributions 
1019*19c3b8c2SApple OSS Distributions 	matching = IOService::serviceMatching("IOPlatformExpert");
1020*19c3b8c2SApple OSS Distributions 	assert(matching);
1021*19c3b8c2SApple OSS Distributions 	pe = (IOPlatformExpert *) IOService::waitForMatchingService(matching, 30ULL * kSecondScale);
1022*19c3b8c2SApple OSS Distributions 	matching->release();
1023*19c3b8c2SApple OSS Distributions 	assert(pe);
1024*19c3b8c2SApple OSS Distributions 	// Returns kIOReturnNotPrivileged is the root device is not secure.
1025*19c3b8c2SApple OSS Distributions 	// Returns kIOReturnUnsupported if "SecureRootName" is not implemented.
1026*19c3b8c2SApple OSS Distributions 	result = pe->callPlatformFunction(functionName, false, (void *)rootName, (void *)NULL, (void *)NULL, (void *)NULL);
1027*19c3b8c2SApple OSS Distributions 	functionName->release();
1028*19c3b8c2SApple OSS Distributions 	OSSafeReleaseNULL(pe);
1029*19c3b8c2SApple OSS Distributions 
1030*19c3b8c2SApple OSS Distributions 	if (result == kIOReturnNotPrivileged) {
1031*19c3b8c2SApple OSS Distributions 		mdevremoveall();
1032*19c3b8c2SApple OSS Distributions 	}
1033*19c3b8c2SApple OSS Distributions 
1034*19c3b8c2SApple OSS Distributions #endif  // CONFIG_SECURE_BSD_ROOT
1035*19c3b8c2SApple OSS Distributions }
1036*19c3b8c2SApple OSS Distributions 
1037*19c3b8c2SApple OSS Distributions void *
IOBSDRegistryEntryForDeviceTree(char * path)1038*19c3b8c2SApple OSS Distributions IOBSDRegistryEntryForDeviceTree(char * path)
1039*19c3b8c2SApple OSS Distributions {
1040*19c3b8c2SApple OSS Distributions 	return IORegistryEntry::fromPath(path, gIODTPlane);
1041*19c3b8c2SApple OSS Distributions }
1042*19c3b8c2SApple OSS Distributions 
1043*19c3b8c2SApple OSS Distributions void
IOBSDRegistryEntryRelease(void * entry)1044*19c3b8c2SApple OSS Distributions IOBSDRegistryEntryRelease(void * entry)
1045*19c3b8c2SApple OSS Distributions {
1046*19c3b8c2SApple OSS Distributions 	IORegistryEntry * regEntry = (IORegistryEntry *)entry;
1047*19c3b8c2SApple OSS Distributions 
1048*19c3b8c2SApple OSS Distributions 	if (regEntry) {
1049*19c3b8c2SApple OSS Distributions 		regEntry->release();
1050*19c3b8c2SApple OSS Distributions 	}
1051*19c3b8c2SApple OSS Distributions 	return;
1052*19c3b8c2SApple OSS Distributions }
1053*19c3b8c2SApple OSS Distributions 
1054*19c3b8c2SApple OSS Distributions const void *
IOBSDRegistryEntryGetData(void * entry,char * property_name,int * packet_length)1055*19c3b8c2SApple OSS Distributions IOBSDRegistryEntryGetData(void * entry, char * property_name,
1056*19c3b8c2SApple OSS Distributions     int * packet_length)
1057*19c3b8c2SApple OSS Distributions {
1058*19c3b8c2SApple OSS Distributions 	OSData *            data;
1059*19c3b8c2SApple OSS Distributions 	IORegistryEntry *   regEntry = (IORegistryEntry *)entry;
1060*19c3b8c2SApple OSS Distributions 
1061*19c3b8c2SApple OSS Distributions 	data = (OSData *) regEntry->getProperty(property_name);
1062*19c3b8c2SApple OSS Distributions 	if (data) {
1063*19c3b8c2SApple OSS Distributions 		*packet_length = data->getLength();
1064*19c3b8c2SApple OSS Distributions 		return data->getBytesNoCopy();
1065*19c3b8c2SApple OSS Distributions 	}
1066*19c3b8c2SApple OSS Distributions 	return NULL;
1067*19c3b8c2SApple OSS Distributions }
1068*19c3b8c2SApple OSS Distributions 
1069*19c3b8c2SApple OSS Distributions kern_return_t
IOBSDGetPlatformUUID(uuid_t uuid,mach_timespec_t timeout)1070*19c3b8c2SApple OSS Distributions IOBSDGetPlatformUUID( uuid_t uuid, mach_timespec_t timeout )
1071*19c3b8c2SApple OSS Distributions {
1072*19c3b8c2SApple OSS Distributions 	IOService * resources;
1073*19c3b8c2SApple OSS Distributions 	OSString *  string;
1074*19c3b8c2SApple OSS Distributions 
1075*19c3b8c2SApple OSS Distributions 	resources = IOService::waitForService( IOService::resourceMatching( kIOPlatformUUIDKey ), (timeout.tv_sec || timeout.tv_nsec) ? &timeout : NULL );
1076*19c3b8c2SApple OSS Distributions 	if (resources == NULL) {
1077*19c3b8c2SApple OSS Distributions 		return KERN_OPERATION_TIMED_OUT;
1078*19c3b8c2SApple OSS Distributions 	}
1079*19c3b8c2SApple OSS Distributions 
1080*19c3b8c2SApple OSS Distributions 	string = (OSString *) IOService::getPlatform()->getProvider()->getProperty( kIOPlatformUUIDKey );
1081*19c3b8c2SApple OSS Distributions 	if (string == NULL) {
1082*19c3b8c2SApple OSS Distributions 		return KERN_NOT_SUPPORTED;
1083*19c3b8c2SApple OSS Distributions 	}
1084*19c3b8c2SApple OSS Distributions 
1085*19c3b8c2SApple OSS Distributions 	uuid_parse( string->getCStringNoCopy(), uuid );
1086*19c3b8c2SApple OSS Distributions 
1087*19c3b8c2SApple OSS Distributions 	return KERN_SUCCESS;
1088*19c3b8c2SApple OSS Distributions }
1089*19c3b8c2SApple OSS Distributions } /* extern "C" */
1090*19c3b8c2SApple OSS Distributions 
1091*19c3b8c2SApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1092*19c3b8c2SApple OSS Distributions 
1093*19c3b8c2SApple OSS Distributions #include <sys/conf.h>
1094*19c3b8c2SApple OSS Distributions #include <sys/lock.h>
1095*19c3b8c2SApple OSS Distributions #include <sys/vnode.h>
1096*19c3b8c2SApple OSS Distributions #include <sys/vnode_if.h>
1097*19c3b8c2SApple OSS Distributions #include <sys/vnode_internal.h>
1098*19c3b8c2SApple OSS Distributions #include <sys/fcntl.h>
1099*19c3b8c2SApple OSS Distributions #include <sys/fsctl.h>
1100*19c3b8c2SApple OSS Distributions #include <sys/mount.h>
1101*19c3b8c2SApple OSS Distributions #include <IOKit/IOPolledInterface.h>
1102*19c3b8c2SApple OSS Distributions #include <IOKit/IOBufferMemoryDescriptor.h>
1103*19c3b8c2SApple OSS Distributions 
1104*19c3b8c2SApple OSS Distributions // see HFSIOC_VOLUME_STATUS in APFS/HFS
1105*19c3b8c2SApple OSS Distributions #define HFS_IOCTL_VOLUME_STATUS _IOR('h', 24, u_int32_t)
1106*19c3b8c2SApple OSS Distributions 
1107*19c3b8c2SApple OSS Distributions LCK_GRP_DECLARE(gIOPolledCoreFileGrp, "polled_corefile");
1108*19c3b8c2SApple OSS Distributions LCK_MTX_DECLARE(gIOPolledCoreFileMtx, &gIOPolledCoreFileGrp);
1109*19c3b8c2SApple OSS Distributions 
1110*19c3b8c2SApple OSS Distributions IOPolledFileIOVars * gIOPolledCoreFileVars;
1111*19c3b8c2SApple OSS Distributions kern_return_t gIOPolledCoreFileOpenRet = kIOReturnNotReady;
1112*19c3b8c2SApple OSS Distributions IOPolledCoreFileMode_t gIOPolledCoreFileMode = kIOPolledCoreFileModeNotInitialized;
1113*19c3b8c2SApple OSS Distributions 
1114*19c3b8c2SApple OSS Distributions #if IOPOLLED_COREFILE
1115*19c3b8c2SApple OSS Distributions 
1116*19c3b8c2SApple OSS Distributions #if defined(XNU_TARGET_OS_BRIDGE)
1117*19c3b8c2SApple OSS Distributions // On bridgeOS allocate a 150MB corefile and leave 150MB free
1118*19c3b8c2SApple OSS Distributions #define kIOCoreDumpSize         150ULL*1024ULL*1024ULL
1119*19c3b8c2SApple OSS Distributions #define kIOCoreDumpFreeSize     150ULL*1024ULL*1024ULL
1120*19c3b8c2SApple OSS Distributions 
1121*19c3b8c2SApple OSS Distributions #elif !defined(XNU_TARGET_OS_OSX) /* defined(XNU_TARGET_OS_BRIDGE) */
1122*19c3b8c2SApple OSS Distributions // On embedded devices with >3GB DRAM we allocate a 500MB corefile
1123*19c3b8c2SApple OSS Distributions // otherwise allocate a 350MB corefile. Leave 350 MB free
1124*19c3b8c2SApple OSS Distributions 
1125*19c3b8c2SApple OSS Distributions #define kIOCoreDumpMinSize      350ULL*1024ULL*1024ULL
1126*19c3b8c2SApple OSS Distributions #define kIOCoreDumpLargeSize    500ULL*1024ULL*1024ULL
1127*19c3b8c2SApple OSS Distributions 
1128*19c3b8c2SApple OSS Distributions #define kIOCoreDumpFreeSize     350ULL*1024ULL*1024ULL
1129*19c3b8c2SApple OSS Distributions 
1130*19c3b8c2SApple OSS Distributions #else /* defined(XNU_TARGET_OS_BRIDGE) */
1131*19c3b8c2SApple OSS Distributions // on macOS devices allocate a corefile sized at 1GB / 32GB of DRAM,
1132*19c3b8c2SApple OSS Distributions // fallback to a 1GB corefile and leave at least 1GB free
1133*19c3b8c2SApple OSS Distributions #define kIOCoreDumpMinSize              1024ULL*1024ULL*1024ULL
1134*19c3b8c2SApple OSS Distributions #define kIOCoreDumpIncrementalSize      1024ULL*1024ULL*1024ULL
1135*19c3b8c2SApple OSS Distributions 
1136*19c3b8c2SApple OSS Distributions #define kIOCoreDumpFreeSize     1024ULL*1024ULL*1024ULL
1137*19c3b8c2SApple OSS Distributions 
1138*19c3b8c2SApple OSS Distributions // on older macOS devices we allocate a 1MB file at boot
1139*19c3b8c2SApple OSS Distributions // to store a panic time stackshot
1140*19c3b8c2SApple OSS Distributions #define kIOStackshotFileSize    1024ULL*1024ULL
1141*19c3b8c2SApple OSS Distributions 
1142*19c3b8c2SApple OSS Distributions #endif /* defined(XNU_TARGET_OS_BRIDGE) */
1143*19c3b8c2SApple OSS Distributions 
1144*19c3b8c2SApple OSS Distributions static IOPolledCoreFileMode_t
GetCoreFileMode()1145*19c3b8c2SApple OSS Distributions GetCoreFileMode()
1146*19c3b8c2SApple OSS Distributions {
1147*19c3b8c2SApple OSS Distributions 	if (on_device_corefile_enabled()) {
1148*19c3b8c2SApple OSS Distributions 		return kIOPolledCoreFileModeCoredump;
1149*19c3b8c2SApple OSS Distributions 	} else if (panic_stackshot_to_disk_enabled()) {
1150*19c3b8c2SApple OSS Distributions 		return kIOPolledCoreFileModeStackshot;
1151*19c3b8c2SApple OSS Distributions 	} else {
1152*19c3b8c2SApple OSS Distributions 		return kIOPolledCoreFileModeDisabled;
1153*19c3b8c2SApple OSS Distributions 	}
1154*19c3b8c2SApple OSS Distributions }
1155*19c3b8c2SApple OSS Distributions 
1156*19c3b8c2SApple OSS Distributions static void
IOCoreFileGetSize(uint64_t * ideal_size,uint64_t * fallback_size,uint64_t * free_space_to_leave,IOPolledCoreFileMode_t mode)1157*19c3b8c2SApple OSS Distributions IOCoreFileGetSize(uint64_t *ideal_size, uint64_t *fallback_size, uint64_t *free_space_to_leave, IOPolledCoreFileMode_t mode)
1158*19c3b8c2SApple OSS Distributions {
1159*19c3b8c2SApple OSS Distributions 	unsigned int requested_corefile_size = 0;
1160*19c3b8c2SApple OSS Distributions 
1161*19c3b8c2SApple OSS Distributions 	*ideal_size = *fallback_size = *free_space_to_leave = 0;
1162*19c3b8c2SApple OSS Distributions 
1163*19c3b8c2SApple OSS Distributions 	// If a custom size was requested, override the ideal and requested sizes
1164*19c3b8c2SApple OSS Distributions 	if (PE_parse_boot_argn("corefile_size_mb", &requested_corefile_size,
1165*19c3b8c2SApple OSS Distributions 	    sizeof(requested_corefile_size))) {
1166*19c3b8c2SApple OSS Distributions 		IOLog("Boot-args specify %d MB kernel corefile\n", requested_corefile_size);
1167*19c3b8c2SApple OSS Distributions 
1168*19c3b8c2SApple OSS Distributions 		*ideal_size = *fallback_size = (requested_corefile_size * 1024ULL * 1024ULL);
1169*19c3b8c2SApple OSS Distributions 		return;
1170*19c3b8c2SApple OSS Distributions 	}
1171*19c3b8c2SApple OSS Distributions 
1172*19c3b8c2SApple OSS Distributions 	unsigned int status_flags = 0;
1173*19c3b8c2SApple OSS Distributions 	int error = VNOP_IOCTL(rootvnode, HFS_IOCTL_VOLUME_STATUS, (caddr_t)&status_flags, 0,
1174*19c3b8c2SApple OSS Distributions 	    vfs_context_kernel());
1175*19c3b8c2SApple OSS Distributions 	if (!error) {
1176*19c3b8c2SApple OSS Distributions 		if (status_flags & (VQ_VERYLOWDISK | VQ_LOWDISK | VQ_NEARLOWDISK)) {
1177*19c3b8c2SApple OSS Distributions 			IOLog("Volume is low on space. Not allocating kernel corefile.\n");
1178*19c3b8c2SApple OSS Distributions 			return;
1179*19c3b8c2SApple OSS Distributions 		}
1180*19c3b8c2SApple OSS Distributions 	} else {
1181*19c3b8c2SApple OSS Distributions 		IOLog("Couldn't retrieve volume status. Error %d\n", error);
1182*19c3b8c2SApple OSS Distributions 	}
1183*19c3b8c2SApple OSS Distributions 
1184*19c3b8c2SApple OSS Distributions #if defined(XNU_TARGET_OS_BRIDGE)
1185*19c3b8c2SApple OSS Distributions #pragma unused(mode)
1186*19c3b8c2SApple OSS Distributions 	*ideal_size = *fallback_size = kIOCoreDumpSize;
1187*19c3b8c2SApple OSS Distributions 	*free_space_to_leave = kIOCoreDumpFreeSize;
1188*19c3b8c2SApple OSS Distributions #elif !defined(XNU_TARGET_OS_OSX) /* defined(XNU_TARGET_OS_BRIDGE) */
1189*19c3b8c2SApple OSS Distributions #pragma unused(mode)
1190*19c3b8c2SApple OSS Distributions 	*ideal_size = *fallback_size = kIOCoreDumpMinSize;
1191*19c3b8c2SApple OSS Distributions 
1192*19c3b8c2SApple OSS Distributions 	if (max_mem > (3 * 1024ULL * 1024ULL * 1024ULL)) {
1193*19c3b8c2SApple OSS Distributions 		*ideal_size = kIOCoreDumpLargeSize;
1194*19c3b8c2SApple OSS Distributions 	}
1195*19c3b8c2SApple OSS Distributions 
1196*19c3b8c2SApple OSS Distributions 	*free_space_to_leave = kIOCoreDumpFreeSize;
1197*19c3b8c2SApple OSS Distributions #else /* defined(XNU_TARGET_OS_BRIDGE) */
1198*19c3b8c2SApple OSS Distributions 	if (mode == kIOPolledCoreFileModeCoredump) {
1199*19c3b8c2SApple OSS Distributions 		*ideal_size = *fallback_size = kIOCoreDumpMinSize;
1200*19c3b8c2SApple OSS Distributions 		if (kIOCoreDumpIncrementalSize != 0 && max_mem > (32 * 1024ULL * 1024ULL * 1024ULL)) {
1201*19c3b8c2SApple OSS Distributions 			*ideal_size = ((ROUNDUP(max_mem, (32 * 1024ULL * 1024ULL * 1024ULL)) / (32 * 1024ULL * 1024ULL * 1024ULL)) * kIOCoreDumpIncrementalSize);
1202*19c3b8c2SApple OSS Distributions 		}
1203*19c3b8c2SApple OSS Distributions 		*free_space_to_leave = kIOCoreDumpFreeSize;
1204*19c3b8c2SApple OSS Distributions 	} else if (mode == kIOPolledCoreFileModeStackshot) {
1205*19c3b8c2SApple OSS Distributions 		*ideal_size = *fallback_size = *free_space_to_leave = kIOStackshotFileSize;
1206*19c3b8c2SApple OSS Distributions 	}
1207*19c3b8c2SApple OSS Distributions #endif /* defined(XNU_TARGET_OS_BRIDGE) */
1208*19c3b8c2SApple OSS Distributions 
1209*19c3b8c2SApple OSS Distributions 	return;
1210*19c3b8c2SApple OSS Distributions }
1211*19c3b8c2SApple OSS Distributions 
1212*19c3b8c2SApple OSS Distributions static IOReturn
IOAccessCoreFileData(void * context,boolean_t write,uint64_t offset,int length,void * buffer)1213*19c3b8c2SApple OSS Distributions IOAccessCoreFileData(void *context, boolean_t write, uint64_t offset, int length, void *buffer)
1214*19c3b8c2SApple OSS Distributions {
1215*19c3b8c2SApple OSS Distributions 	errno_t vnode_error = 0;
1216*19c3b8c2SApple OSS Distributions 	vfs_context_t vfs_context;
1217*19c3b8c2SApple OSS Distributions 	vnode_t vnode_ptr = (vnode_t) context;
1218*19c3b8c2SApple OSS Distributions 
1219*19c3b8c2SApple OSS Distributions 	vfs_context = vfs_context_kernel();
1220*19c3b8c2SApple OSS Distributions 	vnode_error = vn_rdwr(write ? UIO_WRITE : UIO_READ, vnode_ptr, (caddr_t)buffer, length, offset,
1221*19c3b8c2SApple OSS Distributions 	    UIO_SYSSPACE, IO_SWAP_DISPATCH | IO_SYNC | IO_NOCACHE | IO_UNIT, vfs_context_ucred(vfs_context), NULL, vfs_context_proc(vfs_context));
1222*19c3b8c2SApple OSS Distributions 
1223*19c3b8c2SApple OSS Distributions 	if (vnode_error) {
1224*19c3b8c2SApple OSS Distributions 		IOLog("Failed to %s the corefile. Error %d\n", write ? "write to" : "read from", vnode_error);
1225*19c3b8c2SApple OSS Distributions 		return kIOReturnError;
1226*19c3b8c2SApple OSS Distributions 	}
1227*19c3b8c2SApple OSS Distributions 
1228*19c3b8c2SApple OSS Distributions 	return kIOReturnSuccess;
1229*19c3b8c2SApple OSS Distributions }
1230*19c3b8c2SApple OSS Distributions 
1231*19c3b8c2SApple OSS Distributions static void
IOOpenPolledCoreFile(thread_call_param_t __unused,thread_call_param_t corefilename)1232*19c3b8c2SApple OSS Distributions IOOpenPolledCoreFile(thread_call_param_t __unused, thread_call_param_t corefilename)
1233*19c3b8c2SApple OSS Distributions {
1234*19c3b8c2SApple OSS Distributions 	assert(corefilename != NULL);
1235*19c3b8c2SApple OSS Distributions 
1236*19c3b8c2SApple OSS Distributions 	IOReturn err;
1237*19c3b8c2SApple OSS Distributions 	char *filename = (char *) corefilename;
1238*19c3b8c2SApple OSS Distributions 	uint64_t corefile_size_bytes = 0, corefile_fallback_size_bytes = 0, free_space_to_leave_bytes = 0;
1239*19c3b8c2SApple OSS Distributions 	IOPolledCoreFileMode_t mode_to_init = GetCoreFileMode();
1240*19c3b8c2SApple OSS Distributions 
1241*19c3b8c2SApple OSS Distributions 	if (gIOPolledCoreFileVars) {
1242*19c3b8c2SApple OSS Distributions 		return;
1243*19c3b8c2SApple OSS Distributions 	}
1244*19c3b8c2SApple OSS Distributions 	if (!IOPolledInterface::gMetaClass.getInstanceCount()) {
1245*19c3b8c2SApple OSS Distributions 		return;
1246*19c3b8c2SApple OSS Distributions 	}
1247*19c3b8c2SApple OSS Distributions 
1248*19c3b8c2SApple OSS Distributions 	if (gIOPolledCoreFileMode == kIOPolledCoreFileModeUnlinked) {
1249*19c3b8c2SApple OSS Distributions 		return;
1250*19c3b8c2SApple OSS Distributions 	}
1251*19c3b8c2SApple OSS Distributions 
1252*19c3b8c2SApple OSS Distributions 	if (mode_to_init == kIOPolledCoreFileModeDisabled) {
1253*19c3b8c2SApple OSS Distributions 		gIOPolledCoreFileMode = kIOPolledCoreFileModeDisabled;
1254*19c3b8c2SApple OSS Distributions 		return;
1255*19c3b8c2SApple OSS Distributions 	}
1256*19c3b8c2SApple OSS Distributions 
1257*19c3b8c2SApple OSS Distributions 	// We'll overwrite this once we open the file, we update this to mark that we have made
1258*19c3b8c2SApple OSS Distributions 	// it past initialization
1259*19c3b8c2SApple OSS Distributions 	gIOPolledCoreFileMode = kIOPolledCoreFileModeClosed;
1260*19c3b8c2SApple OSS Distributions 
1261*19c3b8c2SApple OSS Distributions 	IOCoreFileGetSize(&corefile_size_bytes, &corefile_fallback_size_bytes, &free_space_to_leave_bytes, mode_to_init);
1262*19c3b8c2SApple OSS Distributions 
1263*19c3b8c2SApple OSS Distributions 	if (corefile_size_bytes == 0 && corefile_fallback_size_bytes == 0) {
1264*19c3b8c2SApple OSS Distributions 		gIOPolledCoreFileMode = kIOPolledCoreFileModeUnlinked;
1265*19c3b8c2SApple OSS Distributions 		return;
1266*19c3b8c2SApple OSS Distributions 	}
1267*19c3b8c2SApple OSS Distributions 
1268*19c3b8c2SApple OSS Distributions 	do {
1269*19c3b8c2SApple OSS Distributions 		err = IOPolledFileOpen(filename, kIOPolledFileCreate, corefile_size_bytes, free_space_to_leave_bytes,
1270*19c3b8c2SApple OSS Distributions 		    NULL, 0, &gIOPolledCoreFileVars, NULL, NULL, NULL);
1271*19c3b8c2SApple OSS Distributions 		if (kIOReturnSuccess == err) {
1272*19c3b8c2SApple OSS Distributions 			break;
1273*19c3b8c2SApple OSS Distributions 		} else if (kIOReturnNoSpace == err) {
1274*19c3b8c2SApple OSS Distributions 			IOLog("Failed to open corefile of size %llu MB (low disk space)",
1275*19c3b8c2SApple OSS Distributions 			    (corefile_size_bytes / (1024ULL * 1024ULL)));
1276*19c3b8c2SApple OSS Distributions 			if (corefile_size_bytes == corefile_fallback_size_bytes) {
1277*19c3b8c2SApple OSS Distributions 				gIOPolledCoreFileOpenRet = err;
1278*19c3b8c2SApple OSS Distributions 				return;
1279*19c3b8c2SApple OSS Distributions 			}
1280*19c3b8c2SApple OSS Distributions 		} else {
1281*19c3b8c2SApple OSS Distributions 			IOLog("Failed to open corefile of size %llu MB (returned error 0x%x)\n",
1282*19c3b8c2SApple OSS Distributions 			    (corefile_size_bytes / (1024ULL * 1024ULL)), err);
1283*19c3b8c2SApple OSS Distributions 			gIOPolledCoreFileOpenRet = err;
1284*19c3b8c2SApple OSS Distributions 			return;
1285*19c3b8c2SApple OSS Distributions 		}
1286*19c3b8c2SApple OSS Distributions 
1287*19c3b8c2SApple OSS Distributions 		err = IOPolledFileOpen(filename, kIOPolledFileCreate, corefile_fallback_size_bytes, free_space_to_leave_bytes,
1288*19c3b8c2SApple OSS Distributions 		    NULL, 0, &gIOPolledCoreFileVars, NULL, NULL, NULL);
1289*19c3b8c2SApple OSS Distributions 		if (kIOReturnSuccess != err) {
1290*19c3b8c2SApple OSS Distributions 			IOLog("Failed to open corefile of size %llu MB (returned error 0x%x)\n",
1291*19c3b8c2SApple OSS Distributions 			    (corefile_fallback_size_bytes / (1024ULL * 1024ULL)), err);
1292*19c3b8c2SApple OSS Distributions 			gIOPolledCoreFileOpenRet = err;
1293*19c3b8c2SApple OSS Distributions 			return;
1294*19c3b8c2SApple OSS Distributions 		}
1295*19c3b8c2SApple OSS Distributions 	} while (false);
1296*19c3b8c2SApple OSS Distributions 
1297*19c3b8c2SApple OSS Distributions 	gIOPolledCoreFileOpenRet = IOPolledFilePollersSetup(gIOPolledCoreFileVars, kIOPolledPreflightCoreDumpState);
1298*19c3b8c2SApple OSS Distributions 	if (kIOReturnSuccess != gIOPolledCoreFileOpenRet) {
1299*19c3b8c2SApple OSS Distributions 		IOPolledFileClose(&gIOPolledCoreFileVars, 0, NULL, 0, 0, 0, false);
1300*19c3b8c2SApple OSS Distributions 		IOLog("IOPolledFilePollersSetup for corefile failed with error: 0x%x\n", err);
1301*19c3b8c2SApple OSS Distributions 	} else {
1302*19c3b8c2SApple OSS Distributions 		IOLog("Opened corefile of size %llu MB\n", (corefile_size_bytes / (1024ULL * 1024ULL)));
1303*19c3b8c2SApple OSS Distributions 		gIOPolledCoreFileMode = mode_to_init;
1304*19c3b8c2SApple OSS Distributions 	}
1305*19c3b8c2SApple OSS Distributions 
1306*19c3b8c2SApple OSS Distributions 	// Provide the "polled file available" callback with a temporary way to read from the file
1307*19c3b8c2SApple OSS Distributions 	(void) IOProvideCoreFileAccess(kdp_core_polled_io_polled_file_available, NULL);
1308*19c3b8c2SApple OSS Distributions 
1309*19c3b8c2SApple OSS Distributions 	return;
1310*19c3b8c2SApple OSS Distributions }
1311*19c3b8c2SApple OSS Distributions 
1312*19c3b8c2SApple OSS Distributions kern_return_t
IOProvideCoreFileAccess(IOCoreFileAccessRecipient recipient,void * recipient_context)1313*19c3b8c2SApple OSS Distributions IOProvideCoreFileAccess(IOCoreFileAccessRecipient recipient, void *recipient_context)
1314*19c3b8c2SApple OSS Distributions {
1315*19c3b8c2SApple OSS Distributions 	kern_return_t error = kIOReturnSuccess;
1316*19c3b8c2SApple OSS Distributions 	errno_t vnode_error = 0;
1317*19c3b8c2SApple OSS Distributions 	vfs_context_t vfs_context;
1318*19c3b8c2SApple OSS Distributions 	vnode_t vnode_ptr;
1319*19c3b8c2SApple OSS Distributions 
1320*19c3b8c2SApple OSS Distributions 	if (!recipient) {
1321*19c3b8c2SApple OSS Distributions 		return kIOReturnBadArgument;
1322*19c3b8c2SApple OSS Distributions 	}
1323*19c3b8c2SApple OSS Distributions 
1324*19c3b8c2SApple OSS Distributions 	if (kIOReturnSuccess != gIOPolledCoreFileOpenRet) {
1325*19c3b8c2SApple OSS Distributions 		return kIOReturnNotReady;
1326*19c3b8c2SApple OSS Distributions 	}
1327*19c3b8c2SApple OSS Distributions 
1328*19c3b8c2SApple OSS Distributions 	// Open the kernel corefile
1329*19c3b8c2SApple OSS Distributions 	vfs_context = vfs_context_kernel();
1330*19c3b8c2SApple OSS Distributions 	vnode_error = vnode_open(kIOCoreDumpPath, (FREAD | FWRITE | O_NOFOLLOW), 0600, 0, &vnode_ptr, vfs_context);
1331*19c3b8c2SApple OSS Distributions 	if (vnode_error) {
1332*19c3b8c2SApple OSS Distributions 		IOLog("Failed to open the corefile. Error %d\n", vnode_error);
1333*19c3b8c2SApple OSS Distributions 		return kIOReturnError;
1334*19c3b8c2SApple OSS Distributions 	}
1335*19c3b8c2SApple OSS Distributions 
1336*19c3b8c2SApple OSS Distributions 	// Call the recipient function
1337*19c3b8c2SApple OSS Distributions 	error = recipient(IOAccessCoreFileData, (void *)vnode_ptr, recipient_context);
1338*19c3b8c2SApple OSS Distributions 
1339*19c3b8c2SApple OSS Distributions 	// Close the kernel corefile
1340*19c3b8c2SApple OSS Distributions 	vnode_close(vnode_ptr, FREAD | FWRITE, vfs_context);
1341*19c3b8c2SApple OSS Distributions 
1342*19c3b8c2SApple OSS Distributions 	return error;
1343*19c3b8c2SApple OSS Distributions }
1344*19c3b8c2SApple OSS Distributions 
1345*19c3b8c2SApple OSS Distributions static void
IOClosePolledCoreFile(void)1346*19c3b8c2SApple OSS Distributions IOClosePolledCoreFile(void)
1347*19c3b8c2SApple OSS Distributions {
1348*19c3b8c2SApple OSS Distributions 	// Notify kdp core that the corefile is no longer available
1349*19c3b8c2SApple OSS Distributions 	(void) kdp_core_polled_io_polled_file_unavailable();
1350*19c3b8c2SApple OSS Distributions 
1351*19c3b8c2SApple OSS Distributions 	gIOPolledCoreFileOpenRet = kIOReturnNotOpen;
1352*19c3b8c2SApple OSS Distributions 	gIOPolledCoreFileMode = kIOPolledCoreFileModeClosed;
1353*19c3b8c2SApple OSS Distributions 	IOPolledFilePollersClose(gIOPolledCoreFileVars, kIOPolledPostflightCoreDumpState);
1354*19c3b8c2SApple OSS Distributions 	IOPolledFileClose(&gIOPolledCoreFileVars, 0, NULL, 0, 0, 0, false);
1355*19c3b8c2SApple OSS Distributions }
1356*19c3b8c2SApple OSS Distributions 
1357*19c3b8c2SApple OSS Distributions static void
IOUnlinkPolledCoreFile(void)1358*19c3b8c2SApple OSS Distributions IOUnlinkPolledCoreFile(void)
1359*19c3b8c2SApple OSS Distributions {
1360*19c3b8c2SApple OSS Distributions 	// Notify kdp core that the corefile is no longer available
1361*19c3b8c2SApple OSS Distributions 	(void) kdp_core_polled_io_polled_file_unavailable();
1362*19c3b8c2SApple OSS Distributions 
1363*19c3b8c2SApple OSS Distributions 	gIOPolledCoreFileOpenRet = kIOReturnNotOpen;
1364*19c3b8c2SApple OSS Distributions 	gIOPolledCoreFileMode = kIOPolledCoreFileModeUnlinked;
1365*19c3b8c2SApple OSS Distributions 	IOPolledFilePollersClose(gIOPolledCoreFileVars, kIOPolledPostflightCoreDumpState);
1366*19c3b8c2SApple OSS Distributions 	IOPolledFileClose(&gIOPolledCoreFileVars, 0, NULL, 0, 0, 0, true);
1367*19c3b8c2SApple OSS Distributions }
1368*19c3b8c2SApple OSS Distributions 
1369*19c3b8c2SApple OSS Distributions #endif /* IOPOLLED_COREFILE */
1370*19c3b8c2SApple OSS Distributions 
1371*19c3b8c2SApple OSS Distributions extern "C" void
IOBSDMountChange(struct mount * mp,uint32_t op)1372*19c3b8c2SApple OSS Distributions IOBSDMountChange(struct mount * mp, uint32_t op)
1373*19c3b8c2SApple OSS Distributions {
1374*19c3b8c2SApple OSS Distributions #if IOPOLLED_COREFILE
1375*19c3b8c2SApple OSS Distributions 	uint64_t flags;
1376*19c3b8c2SApple OSS Distributions 	char path[128];
1377*19c3b8c2SApple OSS Distributions 	int pathLen;
1378*19c3b8c2SApple OSS Distributions 	vnode_t vn;
1379*19c3b8c2SApple OSS Distributions 	int result;
1380*19c3b8c2SApple OSS Distributions 
1381*19c3b8c2SApple OSS Distributions 	lck_mtx_lock(&gIOPolledCoreFileMtx);
1382*19c3b8c2SApple OSS Distributions 
1383*19c3b8c2SApple OSS Distributions 	switch (op) {
1384*19c3b8c2SApple OSS Distributions 	case kIOMountChangeMount:
1385*19c3b8c2SApple OSS Distributions 	case kIOMountChangeDidResize:
1386*19c3b8c2SApple OSS Distributions 
1387*19c3b8c2SApple OSS Distributions 		if (gIOPolledCoreFileVars) {
1388*19c3b8c2SApple OSS Distributions 			break;
1389*19c3b8c2SApple OSS Distributions 		}
1390*19c3b8c2SApple OSS Distributions 		flags = vfs_flags(mp);
1391*19c3b8c2SApple OSS Distributions 		if (MNT_RDONLY & flags) {
1392*19c3b8c2SApple OSS Distributions 			break;
1393*19c3b8c2SApple OSS Distributions 		}
1394*19c3b8c2SApple OSS Distributions 		if (!(MNT_LOCAL & flags)) {
1395*19c3b8c2SApple OSS Distributions 			break;
1396*19c3b8c2SApple OSS Distributions 		}
1397*19c3b8c2SApple OSS Distributions 
1398*19c3b8c2SApple OSS Distributions 		vn = vfs_vnodecovered(mp);
1399*19c3b8c2SApple OSS Distributions 		if (!vn) {
1400*19c3b8c2SApple OSS Distributions 			break;
1401*19c3b8c2SApple OSS Distributions 		}
1402*19c3b8c2SApple OSS Distributions 		pathLen = sizeof(path);
1403*19c3b8c2SApple OSS Distributions 		result = vn_getpath(vn, &path[0], &pathLen);
1404*19c3b8c2SApple OSS Distributions 		vnode_put(vn);
1405*19c3b8c2SApple OSS Distributions 		if (0 != result) {
1406*19c3b8c2SApple OSS Distributions 			break;
1407*19c3b8c2SApple OSS Distributions 		}
1408*19c3b8c2SApple OSS Distributions 		if (!pathLen) {
1409*19c3b8c2SApple OSS Distributions 			break;
1410*19c3b8c2SApple OSS Distributions 		}
1411*19c3b8c2SApple OSS Distributions #if defined(XNU_TARGET_OS_BRIDGE)
1412*19c3b8c2SApple OSS Distributions 		// on bridgeOS systems we put the core in /private/var/internal. We don't
1413*19c3b8c2SApple OSS Distributions 		// want to match with /private/var because /private/var/internal is often mounted
1414*19c3b8c2SApple OSS Distributions 		// over /private/var
1415*19c3b8c2SApple OSS Distributions 		if ((pathLen - 1) < (int) strlen("/private/var/internal")) {
1416*19c3b8c2SApple OSS Distributions 			break;
1417*19c3b8c2SApple OSS Distributions 		}
1418*19c3b8c2SApple OSS Distributions #endif
1419*19c3b8c2SApple OSS Distributions 		if (0 != strncmp(path, kIOCoreDumpPath, pathLen - 1)) {
1420*19c3b8c2SApple OSS Distributions 			break;
1421*19c3b8c2SApple OSS Distributions 		}
1422*19c3b8c2SApple OSS Distributions 
1423*19c3b8c2SApple OSS Distributions 		thread_call_enter1(corefile_open_call, (void *) kIOCoreDumpPath);
1424*19c3b8c2SApple OSS Distributions 		break;
1425*19c3b8c2SApple OSS Distributions 
1426*19c3b8c2SApple OSS Distributions 	case kIOMountChangeUnmount:
1427*19c3b8c2SApple OSS Distributions 	case kIOMountChangeWillResize:
1428*19c3b8c2SApple OSS Distributions 		if (gIOPolledCoreFileVars && (mp == kern_file_mount(gIOPolledCoreFileVars->fileRef))) {
1429*19c3b8c2SApple OSS Distributions 			thread_call_cancel_wait(corefile_open_call);
1430*19c3b8c2SApple OSS Distributions 			IOClosePolledCoreFile();
1431*19c3b8c2SApple OSS Distributions 		}
1432*19c3b8c2SApple OSS Distributions 		break;
1433*19c3b8c2SApple OSS Distributions 	}
1434*19c3b8c2SApple OSS Distributions 
1435*19c3b8c2SApple OSS Distributions 	lck_mtx_unlock(&gIOPolledCoreFileMtx);
1436*19c3b8c2SApple OSS Distributions #endif /* IOPOLLED_COREFILE */
1437*19c3b8c2SApple OSS Distributions }
1438*19c3b8c2SApple OSS Distributions 
1439*19c3b8c2SApple OSS Distributions extern "C" void
IOBSDLowSpaceUnlinkKernelCore(void)1440*19c3b8c2SApple OSS Distributions IOBSDLowSpaceUnlinkKernelCore(void)
1441*19c3b8c2SApple OSS Distributions {
1442*19c3b8c2SApple OSS Distributions #if IOPOLLED_COREFILE
1443*19c3b8c2SApple OSS Distributions 	lck_mtx_lock(&gIOPolledCoreFileMtx);
1444*19c3b8c2SApple OSS Distributions 	if (gIOPolledCoreFileVars) {
1445*19c3b8c2SApple OSS Distributions 		thread_call_cancel_wait(corefile_open_call);
1446*19c3b8c2SApple OSS Distributions 		IOUnlinkPolledCoreFile();
1447*19c3b8c2SApple OSS Distributions 	}
1448*19c3b8c2SApple OSS Distributions 	lck_mtx_unlock(&gIOPolledCoreFileMtx);
1449*19c3b8c2SApple OSS Distributions #endif
1450*19c3b8c2SApple OSS Distributions }
1451*19c3b8c2SApple OSS Distributions 
1452*19c3b8c2SApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1453*19c3b8c2SApple OSS Distributions 
1454*19c3b8c2SApple OSS Distributions extern "C"
1455*19c3b8c2SApple OSS Distributions OS_ALWAYS_INLINE
1456*19c3b8c2SApple OSS Distributions boolean_t
IOCurrentTaskHasStringEntitlement(const char * entitlement,const char * value)1457*19c3b8c2SApple OSS Distributions IOCurrentTaskHasStringEntitlement(const char *entitlement, const char *value)
1458*19c3b8c2SApple OSS Distributions {
1459*19c3b8c2SApple OSS Distributions 	return IOTaskHasStringEntitlement(NULL, entitlement, value);
1460*19c3b8c2SApple OSS Distributions }
1461*19c3b8c2SApple OSS Distributions 
1462*19c3b8c2SApple OSS Distributions extern "C" boolean_t
IOTaskHasStringEntitlement(task_t task,const char * entitlement,const char * value)1463*19c3b8c2SApple OSS Distributions IOTaskHasStringEntitlement(task_t task, const char *entitlement, const char *value)
1464*19c3b8c2SApple OSS Distributions {
1465*19c3b8c2SApple OSS Distributions 	if (task == kernel_task) {
1466*19c3b8c2SApple OSS Distributions 		return false;
1467*19c3b8c2SApple OSS Distributions 	} else if (!entitlement || !value) {
1468*19c3b8c2SApple OSS Distributions 		return false;
1469*19c3b8c2SApple OSS Distributions 	}
1470*19c3b8c2SApple OSS Distributions 
1471*19c3b8c2SApple OSS Distributions 	size_t name_length = strnlen(entitlement, CE_MAX_KEY_SIZE);
1472*19c3b8c2SApple OSS Distributions 	if (name_length >= CE_MAX_KEY_SIZE) {
1473*19c3b8c2SApple OSS Distributions 		printf("entitlement name length exceeds maximum allowed\n");
1474*19c3b8c2SApple OSS Distributions 		return false;
1475*19c3b8c2SApple OSS Distributions 	}
1476*19c3b8c2SApple OSS Distributions 
1477*19c3b8c2SApple OSS Distributions 	size_t value_length = strnlen(value, CE_MAX_KEY_SIZE);
1478*19c3b8c2SApple OSS Distributions 	if (value_length >= CE_MAX_KEY_SIZE) {
1479*19c3b8c2SApple OSS Distributions 		printf("entitlement value length exceeds maximum allowed\n");
1480*19c3b8c2SApple OSS Distributions 		return false;
1481*19c3b8c2SApple OSS Distributions 	}
1482*19c3b8c2SApple OSS Distributions 
1483*19c3b8c2SApple OSS Distributions 	CEQuery_t query = {
1484*19c3b8c2SApple OSS Distributions 		CESelectDictValueDynamic((const uint8_t*)entitlement, name_length),
1485*19c3b8c2SApple OSS Distributions 		CEIsDynamicStringAllowed((const uint8_t*)value, value_length)
1486*19c3b8c2SApple OSS Distributions 	};
1487*19c3b8c2SApple OSS Distributions 
1488*19c3b8c2SApple OSS Distributions #if PMAP_CS_ENABLE && !CONFIG_X86_64_COMPAT
1489*19c3b8c2SApple OSS Distributions 
1490*19c3b8c2SApple OSS Distributions 	/*
1491*19c3b8c2SApple OSS Distributions 	 * If we have PMAP_CS available and code signing is enabled, then we perform
1492*19c3b8c2SApple OSS Distributions 	 * the entitlement check in the PPL.
1493*19c3b8c2SApple OSS Distributions 	 *
1494*19c3b8c2SApple OSS Distributions 	 * Note that the security benefits of doing so are questionable. The PPL has
1495*19c3b8c2SApple OSS Distributions 	 * already locked down the entitlements blob, so we could simply have XNU go
1496*19c3b8c2SApple OSS Distributions 	 * through the locked entitlements blob instead of switching into the PPL to
1497*19c3b8c2SApple OSS Distributions 	 * perform the check. Afterall, the entitlement will be enforced by XNU and
1498*19c3b8c2SApple OSS Distributions 	 * not the PPL, so trapping into the PPL for the check means little.
1499*19c3b8c2SApple OSS Distributions 	 *
1500*19c3b8c2SApple OSS Distributions 	 * Nevertheless, this is kept around to be consistent with how some of the
1501*19c3b8c2SApple OSS Distributions 	 * other interfaces perform their entitlement checks.
1502*19c3b8c2SApple OSS Distributions 	 */
1503*19c3b8c2SApple OSS Distributions 
1504*19c3b8c2SApple OSS Distributions 	if (pmap_cs_enabled()) {
1505*19c3b8c2SApple OSS Distributions 		if (task == NULL || task == current_task()) {
1506*19c3b8c2SApple OSS Distributions 			/* NULL task implies current_task */
1507*19c3b8c2SApple OSS Distributions 			return pmap_query_entitlements(NULL, query, 2, NULL);
1508*19c3b8c2SApple OSS Distributions 		}
1509*19c3b8c2SApple OSS Distributions 
1510*19c3b8c2SApple OSS Distributions 		vm_map_t task_map = get_task_map_reference(task);
1511*19c3b8c2SApple OSS Distributions 		if (task_map) {
1512*19c3b8c2SApple OSS Distributions 			pmap_t pmap = vm_map_get_pmap(task_map);
1513*19c3b8c2SApple OSS Distributions 			if (pmap && pmap_query_entitlements(pmap, query, 2, NULL)) {
1514*19c3b8c2SApple OSS Distributions 				vm_map_deallocate(task_map);
1515*19c3b8c2SApple OSS Distributions 				return true;
1516*19c3b8c2SApple OSS Distributions 			}
1517*19c3b8c2SApple OSS Distributions 			vm_map_deallocate(task_map);
1518*19c3b8c2SApple OSS Distributions 		}
1519*19c3b8c2SApple OSS Distributions 		return false;
1520*19c3b8c2SApple OSS Distributions 	}
1521*19c3b8c2SApple OSS Distributions 
1522*19c3b8c2SApple OSS Distributions #endif
1523*19c3b8c2SApple OSS Distributions 
1524*19c3b8c2SApple OSS Distributions 	/* AMFI interface needs to be available */
1525*19c3b8c2SApple OSS Distributions 	if (amfi == NULL) {
1526*19c3b8c2SApple OSS Distributions 		panic("CoreEntitlements: (IOTask): AMFI interface not available");
1527*19c3b8c2SApple OSS Distributions 	}
1528*19c3b8c2SApple OSS Distributions 
1529*19c3b8c2SApple OSS Distributions 	if (task == NULL) {
1530*19c3b8c2SApple OSS Distributions 		/* NULL task implies current_task */
1531*19c3b8c2SApple OSS Distributions 		task = current_task();
1532*19c3b8c2SApple OSS Distributions 	}
1533*19c3b8c2SApple OSS Distributions 
1534*19c3b8c2SApple OSS Distributions 	proc_t p = (proc_t)get_bsdtask_info(task);
1535*19c3b8c2SApple OSS Distributions 	if (p == NULL) {
1536*19c3b8c2SApple OSS Distributions 		/* Cannot proceed if we don't have a proc structure */
1537*19c3b8c2SApple OSS Distributions 		return false;
1538*19c3b8c2SApple OSS Distributions 	}
1539*19c3b8c2SApple OSS Distributions 
1540*19c3b8c2SApple OSS Distributions 	struct cs_blob* csblob = csproc_get_blob(p);
1541*19c3b8c2SApple OSS Distributions 	if (csblob == NULL) {
1542*19c3b8c2SApple OSS Distributions 		/* Cannot proceed if process doesn't have a code signature */
1543*19c3b8c2SApple OSS Distributions 		return false;
1544*19c3b8c2SApple OSS Distributions 	}
1545*19c3b8c2SApple OSS Distributions 
1546*19c3b8c2SApple OSS Distributions 	void* osents = csblob_os_entitlements_get(csblob);
1547*19c3b8c2SApple OSS Distributions 	if (osents == NULL) {
1548*19c3b8c2SApple OSS Distributions 		return false;
1549*19c3b8c2SApple OSS Distributions 	}
1550*19c3b8c2SApple OSS Distributions 
1551*19c3b8c2SApple OSS Distributions 	CEError_t ce_err = amfi->CoreEntitlements.kQueryCannotBeSatisfied;
1552*19c3b8c2SApple OSS Distributions 	ce_err = amfi->OSEntitlements_query(osents, (uint8_t*)csblob_get_cdhash(csblob), query, 2);
1553*19c3b8c2SApple OSS Distributions 
1554*19c3b8c2SApple OSS Distributions 	return ce_err == amfi->CoreEntitlements.kNoError;
1555*19c3b8c2SApple OSS Distributions }
1556*19c3b8c2SApple OSS Distributions 
1557*19c3b8c2SApple OSS Distributions extern "C"
1558*19c3b8c2SApple OSS Distributions OS_ALWAYS_INLINE
1559*19c3b8c2SApple OSS Distributions boolean_t
IOCurrentTaskHasEntitlement(const char * entitlement)1560*19c3b8c2SApple OSS Distributions IOCurrentTaskHasEntitlement(const char * entitlement)
1561*19c3b8c2SApple OSS Distributions {
1562*19c3b8c2SApple OSS Distributions 	return IOTaskHasEntitlement(NULL, entitlement);
1563*19c3b8c2SApple OSS Distributions }
1564*19c3b8c2SApple OSS Distributions 
1565*19c3b8c2SApple OSS Distributions extern "C" boolean_t
IOTaskHasEntitlement(task_t task,const char * entitlement)1566*19c3b8c2SApple OSS Distributions IOTaskHasEntitlement(task_t task, const char * entitlement)
1567*19c3b8c2SApple OSS Distributions {
1568*19c3b8c2SApple OSS Distributions 	// Don't do this
1569*19c3b8c2SApple OSS Distributions 	if (task == kernel_task || entitlement == NULL) {
1570*19c3b8c2SApple OSS Distributions 		return false;
1571*19c3b8c2SApple OSS Distributions 	}
1572*19c3b8c2SApple OSS Distributions 	size_t entlen = strlen(entitlement);
1573*19c3b8c2SApple OSS Distributions 	CEQuery_t query = {
1574*19c3b8c2SApple OSS Distributions 		CESelectDictValueDynamic((const uint8_t*)entitlement, entlen),
1575*19c3b8c2SApple OSS Distributions 		CEMatchBool(true)
1576*19c3b8c2SApple OSS Distributions 	};
1577*19c3b8c2SApple OSS Distributions 
1578*19c3b8c2SApple OSS Distributions #if PMAP_CS_ENABLE && !CONFIG_X86_64_COMPAT
1579*19c3b8c2SApple OSS Distributions 	if (pmap_cs_enabled()) {
1580*19c3b8c2SApple OSS Distributions 		if (task == NULL || task == current_task()) {
1581*19c3b8c2SApple OSS Distributions 			// NULL task means current task, which translated to the current pmap
1582*19c3b8c2SApple OSS Distributions 			return pmap_query_entitlements(NULL, query, 2, NULL);
1583*19c3b8c2SApple OSS Distributions 		}
1584*19c3b8c2SApple OSS Distributions 		vm_map_t task_map = get_task_map_reference(task);
1585*19c3b8c2SApple OSS Distributions 		if (task_map) {
1586*19c3b8c2SApple OSS Distributions 			pmap_t pmap = vm_map_get_pmap(task_map);
1587*19c3b8c2SApple OSS Distributions 			if (pmap && pmap_query_entitlements(pmap, query, 2, NULL)) {
1588*19c3b8c2SApple OSS Distributions 				vm_map_deallocate(task_map);
1589*19c3b8c2SApple OSS Distributions 				return true;
1590*19c3b8c2SApple OSS Distributions 			}
1591*19c3b8c2SApple OSS Distributions 			vm_map_deallocate(task_map);
1592*19c3b8c2SApple OSS Distributions 		}
1593*19c3b8c2SApple OSS Distributions 		return false;
1594*19c3b8c2SApple OSS Distributions 	}
1595*19c3b8c2SApple OSS Distributions #endif
1596*19c3b8c2SApple OSS Distributions 	if (task == NULL) {
1597*19c3b8c2SApple OSS Distributions 		task = current_task();
1598*19c3b8c2SApple OSS Distributions 	}
1599*19c3b8c2SApple OSS Distributions 
1600*19c3b8c2SApple OSS Distributions 	proc_t p = (proc_t)get_bsdtask_info(task);
1601*19c3b8c2SApple OSS Distributions 
1602*19c3b8c2SApple OSS Distributions 	if (p == NULL) {
1603*19c3b8c2SApple OSS Distributions 		return false;
1604*19c3b8c2SApple OSS Distributions 	}
1605*19c3b8c2SApple OSS Distributions 
1606*19c3b8c2SApple OSS Distributions 	struct cs_blob* csblob = csproc_get_blob(p);
1607*19c3b8c2SApple OSS Distributions 	if (csblob == NULL) {
1608*19c3b8c2SApple OSS Distributions 		return false;
1609*19c3b8c2SApple OSS Distributions 	}
1610*19c3b8c2SApple OSS Distributions 
1611*19c3b8c2SApple OSS Distributions 	void* osents = csblob_os_entitlements_get(csblob);
1612*19c3b8c2SApple OSS Distributions 	if (osents == NULL) {
1613*19c3b8c2SApple OSS Distributions 		return false;
1614*19c3b8c2SApple OSS Distributions 	}
1615*19c3b8c2SApple OSS Distributions 
1616*19c3b8c2SApple OSS Distributions 	if (!amfi) {
1617*19c3b8c2SApple OSS Distributions 		panic("CoreEntitlements: (IOTask): No AMFI\n");
1618*19c3b8c2SApple OSS Distributions 	}
1619*19c3b8c2SApple OSS Distributions 
1620*19c3b8c2SApple OSS Distributions 	return amfi->OSEntitlements_query(osents, (uint8_t*)csblob_get_cdhash(csblob), query, 2) == amfi->CoreEntitlements.kNoError;
1621*19c3b8c2SApple OSS Distributions }
1622*19c3b8c2SApple OSS Distributions 
1623*19c3b8c2SApple OSS Distributions extern "C" boolean_t
IOVnodeHasEntitlement(vnode_t vnode,int64_t off,const char * entitlement)1624*19c3b8c2SApple OSS Distributions IOVnodeHasEntitlement(vnode_t vnode, int64_t off, const char *entitlement)
1625*19c3b8c2SApple OSS Distributions {
1626*19c3b8c2SApple OSS Distributions 	OSObject * obj;
1627*19c3b8c2SApple OSS Distributions 	off_t offset = (off_t)off;
1628*19c3b8c2SApple OSS Distributions 
1629*19c3b8c2SApple OSS Distributions 	obj = IOUserClient::copyClientEntitlementVnode(vnode, offset, entitlement);
1630*19c3b8c2SApple OSS Distributions 	if (!obj) {
1631*19c3b8c2SApple OSS Distributions 		return false;
1632*19c3b8c2SApple OSS Distributions 	}
1633*19c3b8c2SApple OSS Distributions 	obj->release();
1634*19c3b8c2SApple OSS Distributions 	return obj != kOSBooleanFalse;
1635*19c3b8c2SApple OSS Distributions }
1636*19c3b8c2SApple OSS Distributions 
1637*19c3b8c2SApple OSS Distributions extern "C" char *
IOVnodeGetEntitlement(vnode_t vnode,int64_t off,const char * entitlement)1638*19c3b8c2SApple OSS Distributions IOVnodeGetEntitlement(vnode_t vnode, int64_t off, const char *entitlement)
1639*19c3b8c2SApple OSS Distributions {
1640*19c3b8c2SApple OSS Distributions 	OSObject *obj = NULL;
1641*19c3b8c2SApple OSS Distributions 	OSString *str = NULL;
1642*19c3b8c2SApple OSS Distributions 	size_t len;
1643*19c3b8c2SApple OSS Distributions 	char *value = NULL;
1644*19c3b8c2SApple OSS Distributions 	off_t offset = (off_t)off;
1645*19c3b8c2SApple OSS Distributions 
1646*19c3b8c2SApple OSS Distributions 	obj = IOUserClient::copyClientEntitlementVnode(vnode, offset, entitlement);
1647*19c3b8c2SApple OSS Distributions 	if (obj != NULL) {
1648*19c3b8c2SApple OSS Distributions 		str = OSDynamicCast(OSString, obj);
1649*19c3b8c2SApple OSS Distributions 		if (str != NULL) {
1650*19c3b8c2SApple OSS Distributions 			len = str->getLength() + 1;
1651*19c3b8c2SApple OSS Distributions 			value = (char *)kalloc_data(len, Z_WAITOK);
1652*19c3b8c2SApple OSS Distributions 			strlcpy(value, str->getCStringNoCopy(), len);
1653*19c3b8c2SApple OSS Distributions 		}
1654*19c3b8c2SApple OSS Distributions 		obj->release();
1655*19c3b8c2SApple OSS Distributions 	}
1656*19c3b8c2SApple OSS Distributions 	return value;
1657*19c3b8c2SApple OSS Distributions }
1658*19c3b8c2SApple OSS Distributions 
1659*19c3b8c2SApple OSS Distributions extern "C"
1660*19c3b8c2SApple OSS Distributions OS_ALWAYS_INLINE
1661*19c3b8c2SApple OSS Distributions char *
IOCurrentTaskGetEntitlement(const char * entitlement)1662*19c3b8c2SApple OSS Distributions IOCurrentTaskGetEntitlement(const char * entitlement)
1663*19c3b8c2SApple OSS Distributions {
1664*19c3b8c2SApple OSS Distributions 	return IOTaskGetEntitlement(current_task(), entitlement);
1665*19c3b8c2SApple OSS Distributions }
1666*19c3b8c2SApple OSS Distributions 
1667*19c3b8c2SApple OSS Distributions extern "C" char *
IOTaskGetEntitlement(task_t task,const char * entitlement)1668*19c3b8c2SApple OSS Distributions IOTaskGetEntitlement(task_t task, const char * entitlement)
1669*19c3b8c2SApple OSS Distributions {
1670*19c3b8c2SApple OSS Distributions 	OSObject * obj = NULL;
1671*19c3b8c2SApple OSS Distributions 	OSDictionary * entitlements = NULL;
1672*19c3b8c2SApple OSS Distributions 	OSString * str = NULL;
1673*19c3b8c2SApple OSS Distributions 	size_t len = 0;
1674*19c3b8c2SApple OSS Distributions 	char * value = NULL;
1675*19c3b8c2SApple OSS Distributions 
1676*19c3b8c2SApple OSS Distributions 	if (task == kernel_task || task == NULL || entitlement == NULL) {
1677*19c3b8c2SApple OSS Distributions 		goto finish;
1678*19c3b8c2SApple OSS Distributions 	}
1679*19c3b8c2SApple OSS Distributions 
1680*19c3b8c2SApple OSS Distributions 	entitlements = IOUserClient::copyClientEntitlements(task);
1681*19c3b8c2SApple OSS Distributions 	if (entitlements == NULL) {
1682*19c3b8c2SApple OSS Distributions 		goto finish;
1683*19c3b8c2SApple OSS Distributions 	}
1684*19c3b8c2SApple OSS Distributions 
1685*19c3b8c2SApple OSS Distributions 	obj = entitlements->getObject(entitlement);
1686*19c3b8c2SApple OSS Distributions 	str = OSDynamicCast(OSString, obj);
1687*19c3b8c2SApple OSS Distributions 	if (str != NULL) {
1688*19c3b8c2SApple OSS Distributions 		len = str->getLength() + 1;
1689*19c3b8c2SApple OSS Distributions 		value = (char *)kalloc_data(len, (zalloc_flags_t)(Z_ZERO | Z_WAITOK | Z_NOFAIL));
1690*19c3b8c2SApple OSS Distributions 		strlcpy(value, str->getCStringNoCopy(), len);
1691*19c3b8c2SApple OSS Distributions 	}
1692*19c3b8c2SApple OSS Distributions 
1693*19c3b8c2SApple OSS Distributions finish:
1694*19c3b8c2SApple OSS Distributions 	OSSafeReleaseNULL(entitlements);
1695*19c3b8c2SApple OSS Distributions 
1696*19c3b8c2SApple OSS Distributions 	return value;
1697*19c3b8c2SApple OSS Distributions }
1698