xref: /xnu-12377.41.6/bsd/kern/imageboot.c (revision bbb1b6f9e71b8cdde6e5cd6f4841f207dee3d828)
1*bbb1b6f9SApple OSS Distributions /*
2*bbb1b6f9SApple OSS Distributions  * Copyright (c) 2006-2021 Apple Inc. All rights reserved.
3*bbb1b6f9SApple OSS Distributions  *
4*bbb1b6f9SApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5*bbb1b6f9SApple OSS Distributions  *
6*bbb1b6f9SApple OSS Distributions  * This file contains Original Code and/or Modifications of Original Code
7*bbb1b6f9SApple OSS Distributions  * as defined in and that are subject to the Apple Public Source License
8*bbb1b6f9SApple OSS Distributions  * Version 2.0 (the 'License'). You may not use this file except in
9*bbb1b6f9SApple OSS Distributions  * compliance with the License. The rights granted to you under the License
10*bbb1b6f9SApple OSS Distributions  * may not be used to create, or enable the creation or redistribution of,
11*bbb1b6f9SApple OSS Distributions  * unlawful or unlicensed copies of an Apple operating system, or to
12*bbb1b6f9SApple OSS Distributions  * circumvent, violate, or enable the circumvention or violation of, any
13*bbb1b6f9SApple OSS Distributions  * terms of an Apple operating system software license agreement.
14*bbb1b6f9SApple OSS Distributions  *
15*bbb1b6f9SApple OSS Distributions  * Please obtain a copy of the License at
16*bbb1b6f9SApple OSS Distributions  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17*bbb1b6f9SApple OSS Distributions  *
18*bbb1b6f9SApple OSS Distributions  * The Original Code and all software distributed under the License are
19*bbb1b6f9SApple OSS Distributions  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20*bbb1b6f9SApple OSS Distributions  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21*bbb1b6f9SApple OSS Distributions  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22*bbb1b6f9SApple OSS Distributions  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23*bbb1b6f9SApple OSS Distributions  * Please see the License for the specific language governing rights and
24*bbb1b6f9SApple OSS Distributions  * limitations under the License.
25*bbb1b6f9SApple OSS Distributions  *
26*bbb1b6f9SApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27*bbb1b6f9SApple OSS Distributions  */
28*bbb1b6f9SApple OSS Distributions 
29*bbb1b6f9SApple OSS Distributions #include <sys/param.h>
30*bbb1b6f9SApple OSS Distributions #include <sys/kernel.h>
31*bbb1b6f9SApple OSS Distributions #include <sys/proc_internal.h>
32*bbb1b6f9SApple OSS Distributions #include <sys/systm.h>
33*bbb1b6f9SApple OSS Distributions #include <sys/systm.h>
34*bbb1b6f9SApple OSS Distributions #include <sys/mount_internal.h>
35*bbb1b6f9SApple OSS Distributions #include <sys/fsctl.h>
36*bbb1b6f9SApple OSS Distributions #include <sys/filedesc.h>
37*bbb1b6f9SApple OSS Distributions #include <sys/vnode_internal.h>
38*bbb1b6f9SApple OSS Distributions #include <sys/imageboot.h>
39*bbb1b6f9SApple OSS Distributions #include <kern/assert.h>
40*bbb1b6f9SApple OSS Distributions #include <vm/vm_far.h>
41*bbb1b6f9SApple OSS Distributions 
42*bbb1b6f9SApple OSS Distributions #include <sys/namei.h>
43*bbb1b6f9SApple OSS Distributions #include <sys/fcntl.h>
44*bbb1b6f9SApple OSS Distributions #include <sys/vnode.h>
45*bbb1b6f9SApple OSS Distributions #include <sys/xattr.h>
46*bbb1b6f9SApple OSS Distributions #include <sys/sysproto.h>
47*bbb1b6f9SApple OSS Distributions #include <sys/csr.h>
48*bbb1b6f9SApple OSS Distributions #include <miscfs/devfs/devfsdefs.h>
49*bbb1b6f9SApple OSS Distributions #include <libkern/crypto/sha2.h>
50*bbb1b6f9SApple OSS Distributions #include <libkern/crypto/rsa.h>
51*bbb1b6f9SApple OSS Distributions #include <libkern/OSKextLibPrivate.h>
52*bbb1b6f9SApple OSS Distributions #include <sys/ubc_internal.h>
53*bbb1b6f9SApple OSS Distributions 
54*bbb1b6f9SApple OSS Distributions #if CONFIG_IMAGEBOOT_IMG4
55*bbb1b6f9SApple OSS Distributions #include <libkern/img4/interface.h>
56*bbb1b6f9SApple OSS Distributions #include <img4/firmware.h>
57*bbb1b6f9SApple OSS Distributions #endif
58*bbb1b6f9SApple OSS Distributions 
59*bbb1b6f9SApple OSS Distributions #include <kern/kalloc.h>
60*bbb1b6f9SApple OSS Distributions #include <os/overflow.h>
61*bbb1b6f9SApple OSS Distributions #include <vm/vm_kern_xnu.h>
62*bbb1b6f9SApple OSS Distributions 
63*bbb1b6f9SApple OSS Distributions #include <pexpert/pexpert.h>
64*bbb1b6f9SApple OSS Distributions #include <kern/chunklist.h>
65*bbb1b6f9SApple OSS Distributions 
66*bbb1b6f9SApple OSS Distributions extern int (*mountroot)(void);
67*bbb1b6f9SApple OSS Distributions extern char rootdevice[DEVMAXNAMESIZE];
68*bbb1b6f9SApple OSS Distributions 
69*bbb1b6f9SApple OSS Distributions #define DEBUG_IMAGEBOOT 0
70*bbb1b6f9SApple OSS Distributions 
71*bbb1b6f9SApple OSS Distributions #if DEBUG_IMAGEBOOT
72*bbb1b6f9SApple OSS Distributions #define DBG_TRACE(...) printf("imageboot: " __VA_ARGS__)
73*bbb1b6f9SApple OSS Distributions #else
74*bbb1b6f9SApple OSS Distributions #define DBG_TRACE(...) do {} while(0)
75*bbb1b6f9SApple OSS Distributions #endif
76*bbb1b6f9SApple OSS Distributions 
77*bbb1b6f9SApple OSS Distributions #define AUTHDBG(fmt, args...) do { printf("%s: " fmt "\n", __func__, ##args); } while (0)
78*bbb1b6f9SApple OSS Distributions #define AUTHPRNT(fmt, args...) do { printf("%s: " fmt "\n", __func__, ##args); } while (0)
79*bbb1b6f9SApple OSS Distributions 
80*bbb1b6f9SApple OSS Distributions extern int di_root_image_ext(const char *path, char *devname, size_t devsz, dev_t *dev_p, bool removable);
81*bbb1b6f9SApple OSS Distributions extern int di_root_image(const char *path, char *devname, size_t devsz, dev_t *dev_p);
82*bbb1b6f9SApple OSS Distributions extern int di_root_ramfile_buf(void *buf, size_t bufsz, char *devname, size_t devsz, dev_t *dev_p);
83*bbb1b6f9SApple OSS Distributions 
84*bbb1b6f9SApple OSS Distributions static boolean_t imageboot_setup_new(imageboot_type_t type);
85*bbb1b6f9SApple OSS Distributions 
86*bbb1b6f9SApple OSS Distributions void *ubc_getobject_from_filename(const char *filename, struct vnode **vpp, off_t *file_size);
87*bbb1b6f9SApple OSS Distributions 
88*bbb1b6f9SApple OSS Distributions extern lck_rw_t rootvnode_rw_lock;
89*bbb1b6f9SApple OSS Distributions 
90*bbb1b6f9SApple OSS Distributions #define kIBFilePrefix "file://"
91*bbb1b6f9SApple OSS Distributions 
92*bbb1b6f9SApple OSS Distributions __private_extern__ int
imageboot_format_is_valid(const char * root_path)93*bbb1b6f9SApple OSS Distributions imageboot_format_is_valid(const char *root_path)
94*bbb1b6f9SApple OSS Distributions {
95*bbb1b6f9SApple OSS Distributions 	return strncmp(root_path, kIBFilePrefix,
96*bbb1b6f9SApple OSS Distributions 	           strlen(kIBFilePrefix)) == 0;
97*bbb1b6f9SApple OSS Distributions }
98*bbb1b6f9SApple OSS Distributions 
99*bbb1b6f9SApple OSS Distributions static void
vnode_get_and_drop_always(vnode_t vp)100*bbb1b6f9SApple OSS Distributions vnode_get_and_drop_always(vnode_t vp)
101*bbb1b6f9SApple OSS Distributions {
102*bbb1b6f9SApple OSS Distributions 	vnode_getalways(vp);
103*bbb1b6f9SApple OSS Distributions 	vnode_rele(vp);
104*bbb1b6f9SApple OSS Distributions 	vnode_put(vp);
105*bbb1b6f9SApple OSS Distributions }
106*bbb1b6f9SApple OSS Distributions 
107*bbb1b6f9SApple OSS Distributions __private_extern__ bool
imageboot_desired(void)108*bbb1b6f9SApple OSS Distributions imageboot_desired(void)
109*bbb1b6f9SApple OSS Distributions {
110*bbb1b6f9SApple OSS Distributions 	bool do_imageboot = false;
111*bbb1b6f9SApple OSS Distributions 
112*bbb1b6f9SApple OSS Distributions 	char *root_path = NULL;
113*bbb1b6f9SApple OSS Distributions 	root_path = zalloc(ZV_NAMEI);
114*bbb1b6f9SApple OSS Distributions 	/*
115*bbb1b6f9SApple OSS Distributions 	 * Check for first layer DMG rooting.
116*bbb1b6f9SApple OSS Distributions 	 *
117*bbb1b6f9SApple OSS Distributions 	 * Note that here we are principally concerned with whether or not we
118*bbb1b6f9SApple OSS Distributions 	 * SHOULD try to imageboot, not whether or not we are going to be able to.
119*bbb1b6f9SApple OSS Distributions 	 *
120*bbb1b6f9SApple OSS Distributions 	 * If NONE of the boot-args are present, then assume that image-rooting
121*bbb1b6f9SApple OSS Distributions 	 * is not requested.
122*bbb1b6f9SApple OSS Distributions 	 *
123*bbb1b6f9SApple OSS Distributions 	 * [!! Note parens guard the entire logically OR'd set of statements, below. It validates
124*bbb1b6f9SApple OSS Distributions 	 * that NONE of the below-mentioned boot-args is present...!!]
125*bbb1b6f9SApple OSS Distributions 	 */
126*bbb1b6f9SApple OSS Distributions 	if (!(PE_parse_boot_argn("rp0", root_path, MAXPATHLEN) ||
127*bbb1b6f9SApple OSS Distributions #if CONFIG_IMAGEBOOT_IMG4
128*bbb1b6f9SApple OSS Distributions 	    PE_parse_boot_argn("arp0", root_path, MAXPATHLEN) ||
129*bbb1b6f9SApple OSS Distributions #endif
130*bbb1b6f9SApple OSS Distributions 	    PE_parse_boot_argn("rp", root_path, MAXPATHLEN) ||
131*bbb1b6f9SApple OSS Distributions 	    PE_parse_boot_argn(IMAGEBOOT_ROOT_ARG, root_path, MAXPATHLEN) ||
132*bbb1b6f9SApple OSS Distributions 	    PE_parse_boot_argn(IMAGEBOOT_AUTHROOT_ARG, root_path, MAXPATHLEN))) {
133*bbb1b6f9SApple OSS Distributions 		/* explicitly set to false */
134*bbb1b6f9SApple OSS Distributions 		do_imageboot = false;
135*bbb1b6f9SApple OSS Distributions 	} else {
136*bbb1b6f9SApple OSS Distributions 		/* now sanity check the file-path format */
137*bbb1b6f9SApple OSS Distributions 		if (imageboot_format_is_valid(root_path)) {
138*bbb1b6f9SApple OSS Distributions 			DBG_TRACE("%s: Found %s\n", __FUNCTION__, root_path);
139*bbb1b6f9SApple OSS Distributions 			/* root_path looks good and we have one of the aforementioned bootargs */
140*bbb1b6f9SApple OSS Distributions 			do_imageboot = true;
141*bbb1b6f9SApple OSS Distributions 		} else {
142*bbb1b6f9SApple OSS Distributions 			/* explicitly set to false */
143*bbb1b6f9SApple OSS Distributions 			do_imageboot = false;
144*bbb1b6f9SApple OSS Distributions 		}
145*bbb1b6f9SApple OSS Distributions 	}
146*bbb1b6f9SApple OSS Distributions 
147*bbb1b6f9SApple OSS Distributions 	zfree(ZV_NAMEI, root_path);
148*bbb1b6f9SApple OSS Distributions 	return do_imageboot;
149*bbb1b6f9SApple OSS Distributions }
150*bbb1b6f9SApple OSS Distributions 
151*bbb1b6f9SApple OSS Distributions __private_extern__ imageboot_type_t
imageboot_needed(void)152*bbb1b6f9SApple OSS Distributions imageboot_needed(void)
153*bbb1b6f9SApple OSS Distributions {
154*bbb1b6f9SApple OSS Distributions 	imageboot_type_t result = IMAGEBOOT_NONE;
155*bbb1b6f9SApple OSS Distributions 	char *root_path = NULL;
156*bbb1b6f9SApple OSS Distributions 
157*bbb1b6f9SApple OSS Distributions 	DBG_TRACE("%s: checking for presence of root path\n", __FUNCTION__);
158*bbb1b6f9SApple OSS Distributions 
159*bbb1b6f9SApple OSS Distributions 	if (!imageboot_desired()) {
160*bbb1b6f9SApple OSS Distributions 		goto out;
161*bbb1b6f9SApple OSS Distributions 	}
162*bbb1b6f9SApple OSS Distributions 
163*bbb1b6f9SApple OSS Distributions 	root_path = zalloc(ZV_NAMEI);
164*bbb1b6f9SApple OSS Distributions 	result = IMAGEBOOT_DMG;
165*bbb1b6f9SApple OSS Distributions 
166*bbb1b6f9SApple OSS Distributions 	/* Check for second layer */
167*bbb1b6f9SApple OSS Distributions 	if (!(PE_parse_boot_argn("rp1", root_path, MAXPATHLEN) ||
168*bbb1b6f9SApple OSS Distributions 	    PE_parse_boot_argn(IMAGEBOOT_CONTAINER_ARG, root_path, MAXPATHLEN))) {
169*bbb1b6f9SApple OSS Distributions 		goto out;
170*bbb1b6f9SApple OSS Distributions 	}
171*bbb1b6f9SApple OSS Distributions 
172*bbb1b6f9SApple OSS Distributions 	/* Sanity-check second layer */
173*bbb1b6f9SApple OSS Distributions 	if (imageboot_format_is_valid(root_path)) {
174*bbb1b6f9SApple OSS Distributions 		DBG_TRACE("%s: Found %s\n", __FUNCTION__, root_path);
175*bbb1b6f9SApple OSS Distributions 	} else {
176*bbb1b6f9SApple OSS Distributions 		panic("%s: Invalid URL scheme for %s",
177*bbb1b6f9SApple OSS Distributions 		    __FUNCTION__, root_path);
178*bbb1b6f9SApple OSS Distributions 	}
179*bbb1b6f9SApple OSS Distributions 
180*bbb1b6f9SApple OSS Distributions out:
181*bbb1b6f9SApple OSS Distributions 	if (root_path != NULL) {
182*bbb1b6f9SApple OSS Distributions 		zfree(ZV_NAMEI, root_path);
183*bbb1b6f9SApple OSS Distributions 	}
184*bbb1b6f9SApple OSS Distributions 	return result;
185*bbb1b6f9SApple OSS Distributions }
186*bbb1b6f9SApple OSS Distributions 
187*bbb1b6f9SApple OSS Distributions extern bool IOBaseSystemARVRootHashAvailable(void);
188*bbb1b6f9SApple OSS Distributions 
189*bbb1b6f9SApple OSS Distributions 
190*bbb1b6f9SApple OSS Distributions /*
191*bbb1b6f9SApple OSS Distributions  * Mounts new filesystem based on image path, and pivots it to the root.
192*bbb1b6f9SApple OSS Distributions  * The image to be mounted is located at image_path.
193*bbb1b6f9SApple OSS Distributions  * It will be mounted at mount_path.
194*bbb1b6f9SApple OSS Distributions  * The vfs_switch_root operation will be performed.
195*bbb1b6f9SApple OSS Distributions  * After the pivot, the outgoing root filesystem (the filesystem at root when
196*bbb1b6f9SApple OSS Distributions  * this function begins) will be at outgoing_root_path.  If `skip_signature_check` is true,
197*bbb1b6f9SApple OSS Distributions  * then ignore the chunklisted or authAPFS checks on this image
198*bbb1b6f9SApple OSS Distributions  */
199*bbb1b6f9SApple OSS Distributions __private_extern__ int
imageboot_pivot_image(const char * image_path,imageboot_type_t type,const char * mount_path,const char * outgoing_root_path,const bool rooted_dmg,const bool skip_signature_check)200*bbb1b6f9SApple OSS Distributions imageboot_pivot_image(const char *image_path, imageboot_type_t type, const char *mount_path,
201*bbb1b6f9SApple OSS Distributions     const char *outgoing_root_path, const bool rooted_dmg, const bool skip_signature_check)
202*bbb1b6f9SApple OSS Distributions {
203*bbb1b6f9SApple OSS Distributions 	int error = 0;
204*bbb1b6f9SApple OSS Distributions 	boolean_t authenticated_dmg_chunklist = false;
205*bbb1b6f9SApple OSS Distributions 	vnode_t mount_vp = NULLVP;
206*bbb1b6f9SApple OSS Distributions 	errno_t rootauth;
207*bbb1b6f9SApple OSS Distributions 
208*bbb1b6f9SApple OSS Distributions 
209*bbb1b6f9SApple OSS Distributions 	if (type != IMAGEBOOT_DMG) {
210*bbb1b6f9SApple OSS Distributions 		panic("not supported");
211*bbb1b6f9SApple OSS Distributions 	}
212*bbb1b6f9SApple OSS Distributions 
213*bbb1b6f9SApple OSS Distributions 	/*
214*bbb1b6f9SApple OSS Distributions 	 * Check that the image file actually exists.
215*bbb1b6f9SApple OSS Distributions 	 * We also need to find the mount it's on, to mark it as backing the
216*bbb1b6f9SApple OSS Distributions 	 * root.
217*bbb1b6f9SApple OSS Distributions 	 */
218*bbb1b6f9SApple OSS Distributions 	vnode_t imagevp = NULLVP;
219*bbb1b6f9SApple OSS Distributions 	error = vnode_lookup(image_path, 0, &imagevp, vfs_context_kernel());
220*bbb1b6f9SApple OSS Distributions 	if (error) {
221*bbb1b6f9SApple OSS Distributions 		printf("%s: image file not found or couldn't be read: %d\n", __FUNCTION__, error);
222*bbb1b6f9SApple OSS Distributions 		/*
223*bbb1b6f9SApple OSS Distributions 		 * bail out here to short-circuit out of panic logic below.
224*bbb1b6f9SApple OSS Distributions 		 * Failure to find the pivot-image should not be a fatal condition (ENOENT)
225*bbb1b6f9SApple OSS Distributions 		 * since it may result in natural consequences (ergo, cannot unlock filevault prompt).
226*bbb1b6f9SApple OSS Distributions 		 */
227*bbb1b6f9SApple OSS Distributions 		return error;
228*bbb1b6f9SApple OSS Distributions 	}
229*bbb1b6f9SApple OSS Distributions 
230*bbb1b6f9SApple OSS Distributions 	/*
231*bbb1b6f9SApple OSS Distributions 	 * load the disk image and obtain its device.
232*bbb1b6f9SApple OSS Distributions 	 * di_root_image's name and the names of its arguments suggest it has
233*bbb1b6f9SApple OSS Distributions 	 * to be mounted at the root, but that's not actually needed.
234*bbb1b6f9SApple OSS Distributions 	 * We just need to obtain the device info.
235*bbb1b6f9SApple OSS Distributions 	 */
236*bbb1b6f9SApple OSS Distributions 
237*bbb1b6f9SApple OSS Distributions 	dev_t dev;
238*bbb1b6f9SApple OSS Distributions 	char devname[DEVMAXNAMESIZE];
239*bbb1b6f9SApple OSS Distributions 	const char *error_func = NULL;
240*bbb1b6f9SApple OSS Distributions 	unsigned ramdisk_arg = 0;
241*bbb1b6f9SApple OSS Distributions 	(void) PE_parse_boot_argn("-bsdmgroot-ramdisk", &ramdisk_arg, sizeof(ramdisk_arg));
242*bbb1b6f9SApple OSS Distributions 
243*bbb1b6f9SApple OSS Distributions 	if (ramdisk_arg) {
244*bbb1b6f9SApple OSS Distributions 		size_t bufsz = 0;
245*bbb1b6f9SApple OSS Distributions 		void *buf = NULL;
246*bbb1b6f9SApple OSS Distributions 		error_func = "imageboot_read_file";
247*bbb1b6f9SApple OSS Distributions 		// no_softlimit: di_root_ramfile_buf is OK to handle a no_softlimit buffer
248*bbb1b6f9SApple OSS Distributions 		error = imageboot_read_file_pageable(image_path, &buf, &bufsz, /* no_softlimit */ true);
249*bbb1b6f9SApple OSS Distributions 		if (error == 0) {
250*bbb1b6f9SApple OSS Distributions 			error_func = "di_root_ramfile_buf";
251*bbb1b6f9SApple OSS Distributions 			error = di_root_ramfile_buf(buf, bufsz, devname, sizeof(devname), &dev);
252*bbb1b6f9SApple OSS Distributions 		}
253*bbb1b6f9SApple OSS Distributions 		if (error && (buf != NULL)) {
254*bbb1b6f9SApple OSS Distributions 			kmem_free(kernel_map, (vm_offset_t)buf, (vm_size_t)bufsz);
255*bbb1b6f9SApple OSS Distributions 		}
256*bbb1b6f9SApple OSS Distributions 	} else {
257*bbb1b6f9SApple OSS Distributions 		error_func = "di_root_image";
258*bbb1b6f9SApple OSS Distributions 		error = di_root_image_ext(image_path, devname, DEVMAXNAMESIZE, &dev, true);
259*bbb1b6f9SApple OSS Distributions 	}
260*bbb1b6f9SApple OSS Distributions 	if (error) {
261*bbb1b6f9SApple OSS Distributions 		panic("%s: %s failed: %d", __FUNCTION__, error_func, error);
262*bbb1b6f9SApple OSS Distributions 	}
263*bbb1b6f9SApple OSS Distributions 
264*bbb1b6f9SApple OSS Distributions 	printf("%s: attached disk image %s as %s\n", __FUNCTION__, image_path, devname);
265*bbb1b6f9SApple OSS Distributions 
266*bbb1b6f9SApple OSS Distributions 
267*bbb1b6f9SApple OSS Distributions #if CONFIG_IMAGEBOOT_CHUNKLIST
268*bbb1b6f9SApple OSS Distributions 	if ((rooted_dmg == false) && !IOBaseSystemARVRootHashAvailable()) {
269*bbb1b6f9SApple OSS Distributions 		error = authenticate_root_with_chunklist(image_path, NULL);
270*bbb1b6f9SApple OSS Distributions 		if (error == 0) {
271*bbb1b6f9SApple OSS Distributions 			printf("authenticated root-dmg via chunklist...\n");
272*bbb1b6f9SApple OSS Distributions 			authenticated_dmg_chunklist = true;
273*bbb1b6f9SApple OSS Distributions 		} else {
274*bbb1b6f9SApple OSS Distributions 			/* root hash was not available, and image is NOT chunklisted? */
275*bbb1b6f9SApple OSS Distributions 			printf("failed to chunklist-authenticate root-dmg @ %s\n", image_path);
276*bbb1b6f9SApple OSS Distributions 		}
277*bbb1b6f9SApple OSS Distributions 	}
278*bbb1b6f9SApple OSS Distributions #endif
279*bbb1b6f9SApple OSS Distributions 
280*bbb1b6f9SApple OSS Distributions 	char fulldevname[DEVMAXNAMESIZE + 5]; // "/dev/"
281*bbb1b6f9SApple OSS Distributions 	strlcpy(fulldevname, "/dev/", sizeof(fulldevname));
282*bbb1b6f9SApple OSS Distributions 	strlcat(fulldevname, devname, sizeof(fulldevname));
283*bbb1b6f9SApple OSS Distributions 
284*bbb1b6f9SApple OSS Distributions 	/*
285*bbb1b6f9SApple OSS Distributions 	 * mount expects another layer of indirection (because it expects to
286*bbb1b6f9SApple OSS Distributions 	 * be getting a user_addr_t of a char *.
287*bbb1b6f9SApple OSS Distributions 	 * Make a pointer-to-pointer on our stack. It won't use this
288*bbb1b6f9SApple OSS Distributions 	 * address after it returns so this should be safe.
289*bbb1b6f9SApple OSS Distributions 	 */
290*bbb1b6f9SApple OSS Distributions 	char *fulldevnamep = &(fulldevname[0]);
291*bbb1b6f9SApple OSS Distributions 	char **fulldevnamepp = &fulldevnamep;
292*bbb1b6f9SApple OSS Distributions 
293*bbb1b6f9SApple OSS Distributions #define PIVOTMNT "/System/Volumes/BaseSystem"
294*bbb1b6f9SApple OSS Distributions 
295*bbb1b6f9SApple OSS Distributions 
296*bbb1b6f9SApple OSS Distributions 	/* Attempt to mount as HFS; if it fails, then try as APFS */
297*bbb1b6f9SApple OSS Distributions 	printf("%s: attempting to mount as hfs...\n", __FUNCTION__);
298*bbb1b6f9SApple OSS Distributions 	error = kernel_mount("hfs", NULLVP, NULLVP, PIVOTMNT, fulldevnamepp, 0, (MNT_RDONLY | MNT_DONTBROWSE), (KERNEL_MOUNT_NOAUTH | KERNEL_MOUNT_BASESYSTEMROOT), vfs_context_kernel());
299*bbb1b6f9SApple OSS Distributions 	if (error) {
300*bbb1b6f9SApple OSS Distributions 		printf("mount failed: %d\n", error);
301*bbb1b6f9SApple OSS Distributions 		printf("%s: attempting to mount as apfs...\n", __FUNCTION__);
302*bbb1b6f9SApple OSS Distributions 		error = kernel_mount("apfs", NULLVP, NULLVP, PIVOTMNT, fulldevnamepp, 0, (MNT_RDONLY | MNT_DONTBROWSE), (KERNEL_MOUNT_NOAUTH | KERNEL_MOUNT_BASESYSTEMROOT), vfs_context_kernel());
303*bbb1b6f9SApple OSS Distributions 	}
304*bbb1b6f9SApple OSS Distributions 
305*bbb1b6f9SApple OSS Distributions 	/* If we didn't mount as either HFS or APFS, then bail out */
306*bbb1b6f9SApple OSS Distributions 	if (error) {
307*bbb1b6f9SApple OSS Distributions 		/*
308*bbb1b6f9SApple OSS Distributions 		 * Note that for this particular failure case (failure to mount), the disk image
309*bbb1b6f9SApple OSS Distributions 		 * being attached may have failed to quiesce within the alloted time out (20-30 sec).
310*bbb1b6f9SApple OSS Distributions 		 * For example, it may be still probing, or APFS container enumeration may have not
311*bbb1b6f9SApple OSS Distributions 		 * completed. If so, then we may have fallen into this particular error case. However,
312*bbb1b6f9SApple OSS Distributions 		 * failure to complete matching should be an exceptional case as 30 sec. is quite a
313*bbb1b6f9SApple OSS Distributions 		 * long time to wait for matching to complete (which would have occurred in
314*bbb1b6f9SApple OSS Distributions 		 * di_root_image_ext).
315*bbb1b6f9SApple OSS Distributions 		 */
316*bbb1b6f9SApple OSS Distributions #if defined(__arm64__) && XNU_TARGET_OS_OSX
317*bbb1b6f9SApple OSS Distributions 		panic("%s: failed to mount pivot image(%d)!", __FUNCTION__, error);
318*bbb1b6f9SApple OSS Distributions #endif
319*bbb1b6f9SApple OSS Distributions 		printf("%s: failed to mount pivot image(%d) !", __FUNCTION__, error);
320*bbb1b6f9SApple OSS Distributions 		goto done;
321*bbb1b6f9SApple OSS Distributions 	}
322*bbb1b6f9SApple OSS Distributions 
323*bbb1b6f9SApple OSS Distributions 	/* otherwise, if the mount succeeded, then assert that the DMG is authenticated (either chunklist or authapfs) */
324*bbb1b6f9SApple OSS Distributions 	error = vnode_lookup(PIVOTMNT, 0, &mount_vp, vfs_context_kernel());
325*bbb1b6f9SApple OSS Distributions 	if (error) {
326*bbb1b6f9SApple OSS Distributions #if defined(__arm64__) && XNU_TARGET_OS_OSX
327*bbb1b6f9SApple OSS Distributions 		panic("%s: failed to lookup pivot root (%d) !", __FUNCTION__, error);
328*bbb1b6f9SApple OSS Distributions #endif
329*bbb1b6f9SApple OSS Distributions 		printf("%s: failed to lookup pivot root (%d)!", __FUNCTION__, error);
330*bbb1b6f9SApple OSS Distributions 		goto done;
331*bbb1b6f9SApple OSS Distributions 	}
332*bbb1b6f9SApple OSS Distributions 
333*bbb1b6f9SApple OSS Distributions 	/* the 0x1 implies base system */
334*bbb1b6f9SApple OSS Distributions 	rootauth = VNOP_IOCTL(mount_vp, FSIOC_KERNEL_ROOTAUTH, (caddr_t)0x1, 0, vfs_context_kernel());
335*bbb1b6f9SApple OSS Distributions 	if (rootauth) {
336*bbb1b6f9SApple OSS Distributions 		printf("BS-DMG failed to authenticate intra-FS \n");
337*bbb1b6f9SApple OSS Distributions 		/*
338*bbb1b6f9SApple OSS Distributions 		 * If we are using a custom rooted DMG, or if we have already authenticated
339*bbb1b6f9SApple OSS Distributions 		 * the DMG via chunklist, then it is permissible to use.
340*bbb1b6f9SApple OSS Distributions 		 * Or, if CSR_ALLOW_ANY_RECOVERY_OS is set on Development or Debug build variant.
341*bbb1b6f9SApple OSS Distributions 		 */
342*bbb1b6f9SApple OSS Distributions 		if (rooted_dmg || authenticated_dmg_chunklist || skip_signature_check) {
343*bbb1b6f9SApple OSS Distributions 			rootauth = 0;
344*bbb1b6f9SApple OSS Distributions 		}
345*bbb1b6f9SApple OSS Distributions 		error = rootauth;
346*bbb1b6f9SApple OSS Distributions 	}
347*bbb1b6f9SApple OSS Distributions 	vnode_put(mount_vp);
348*bbb1b6f9SApple OSS Distributions 	mount_vp = NULLVP;
349*bbb1b6f9SApple OSS Distributions 
350*bbb1b6f9SApple OSS Distributions 	if (error) {
351*bbb1b6f9SApple OSS Distributions 		/*
352*bbb1b6f9SApple OSS Distributions 		 * Failure here exclusively means that the mount failed to authenticate.
353*bbb1b6f9SApple OSS Distributions 		 * This means that the disk image either was not sealed (authapfs), or it was
354*bbb1b6f9SApple OSS Distributions 		 * not hosted on a chunklisted DMG.  Both scenarios may be fatal depending
355*bbb1b6f9SApple OSS Distributions 		 * on the platform.
356*bbb1b6f9SApple OSS Distributions 		 */
357*bbb1b6f9SApple OSS Distributions #if defined(__arm64__) && XNU_TARGET_OS_OSX
358*bbb1b6f9SApple OSS Distributions 		panic("%s: could not authenticate the pivot image: %d. giving up.", __FUNCTION__, error);
359*bbb1b6f9SApple OSS Distributions #endif
360*bbb1b6f9SApple OSS Distributions 		printf("%s: could not authenticate the pivot image: %d. giving up.\n", __FUNCTION__, error);
361*bbb1b6f9SApple OSS Distributions 		goto done;
362*bbb1b6f9SApple OSS Distributions 	}
363*bbb1b6f9SApple OSS Distributions 
364*bbb1b6f9SApple OSS Distributions 	if (rootvnode) {
365*bbb1b6f9SApple OSS Distributions 		mount_t root_mp = vnode_mount(rootvnode);
366*bbb1b6f9SApple OSS Distributions 		if (root_mp && (root_mp->mnt_kern_flag & MNTK_SSD)) {
367*bbb1b6f9SApple OSS Distributions 			rootvp_is_ssd = true;
368*bbb1b6f9SApple OSS Distributions 		}
369*bbb1b6f9SApple OSS Distributions 	}
370*bbb1b6f9SApple OSS Distributions 	/*
371*bbb1b6f9SApple OSS Distributions 	 * pivot the incoming and outgoing filesystems
372*bbb1b6f9SApple OSS Distributions 	 */
373*bbb1b6f9SApple OSS Distributions 	error = vfs_switch_root(mount_path, outgoing_root_path, 0);
374*bbb1b6f9SApple OSS Distributions 	if (error) {
375*bbb1b6f9SApple OSS Distributions 		panic("%s: vfs_switch_root failed: %d", __FUNCTION__, error);
376*bbb1b6f9SApple OSS Distributions 	}
377*bbb1b6f9SApple OSS Distributions 
378*bbb1b6f9SApple OSS Distributions 	/*
379*bbb1b6f9SApple OSS Distributions 	 * Mark the filesystem containing the image as backing root, so it
380*bbb1b6f9SApple OSS Distributions 	 * won't be unmountable.
381*bbb1b6f9SApple OSS Distributions 	 *
382*bbb1b6f9SApple OSS Distributions 	 * vfs_switch_root() clears this flag, so we have to set it after
383*bbb1b6f9SApple OSS Distributions 	 * the pivot call.
384*bbb1b6f9SApple OSS Distributions 	 * If the system later pivots out of the image, vfs_switch_root
385*bbb1b6f9SApple OSS Distributions 	 * will clear it again, so the backing filesystem can be unmounted.
386*bbb1b6f9SApple OSS Distributions 	 */
387*bbb1b6f9SApple OSS Distributions 	if (!ramdisk_arg) {
388*bbb1b6f9SApple OSS Distributions 		mount_t imagemp = imagevp->v_mount;
389*bbb1b6f9SApple OSS Distributions 		lck_rw_lock_exclusive(&imagemp->mnt_rwlock);
390*bbb1b6f9SApple OSS Distributions 		imagemp->mnt_kern_flag |= MNTK_BACKS_ROOT;
391*bbb1b6f9SApple OSS Distributions 		lck_rw_done(&imagemp->mnt_rwlock);
392*bbb1b6f9SApple OSS Distributions 	}
393*bbb1b6f9SApple OSS Distributions 
394*bbb1b6f9SApple OSS Distributions 	error = 0;
395*bbb1b6f9SApple OSS Distributions 
396*bbb1b6f9SApple OSS Distributions 	/*
397*bbb1b6f9SApple OSS Distributions 	 * Note that we do NOT change kern.bootuuid here -
398*bbb1b6f9SApple OSS Distributions 	 * imageboot_mount_image() does, but imageboot_pivot_image() doesn't.
399*bbb1b6f9SApple OSS Distributions 	 * imageboot_mount_image() is used when the root volume uuid was
400*bbb1b6f9SApple OSS Distributions 	 * "always supposed to be" the one inside the dmg. imageboot_pivot_
401*bbb1b6f9SApple OSS Distributions 	 * image() is used when the true root volume just needs to be
402*bbb1b6f9SApple OSS Distributions 	 * obscured for a moment by the dmg.
403*bbb1b6f9SApple OSS Distributions 	 */
404*bbb1b6f9SApple OSS Distributions 
405*bbb1b6f9SApple OSS Distributions done:
406*bbb1b6f9SApple OSS Distributions 	if (imagevp != NULLVP) {
407*bbb1b6f9SApple OSS Distributions 		vnode_put(imagevp);
408*bbb1b6f9SApple OSS Distributions 	}
409*bbb1b6f9SApple OSS Distributions 	return error;
410*bbb1b6f9SApple OSS Distributions }
411*bbb1b6f9SApple OSS Distributions 
412*bbb1b6f9SApple OSS Distributions /* kern_sysctl.c */
413*bbb1b6f9SApple OSS Distributions extern uuid_string_t fake_bootuuid;
414*bbb1b6f9SApple OSS Distributions 
415*bbb1b6f9SApple OSS Distributions static void
set_fake_bootuuid(mount_t mp)416*bbb1b6f9SApple OSS Distributions set_fake_bootuuid(mount_t mp)
417*bbb1b6f9SApple OSS Distributions {
418*bbb1b6f9SApple OSS Distributions 	struct vfs_attr va;
419*bbb1b6f9SApple OSS Distributions 	VFSATTR_INIT(&va);
420*bbb1b6f9SApple OSS Distributions 	VFSATTR_WANTED(&va, f_uuid);
421*bbb1b6f9SApple OSS Distributions 
422*bbb1b6f9SApple OSS Distributions 	if (vfs_getattr(mp, &va, vfs_context_current()) != 0) {
423*bbb1b6f9SApple OSS Distributions 		return;
424*bbb1b6f9SApple OSS Distributions 	}
425*bbb1b6f9SApple OSS Distributions 
426*bbb1b6f9SApple OSS Distributions 	if (!VFSATTR_IS_SUPPORTED(&va, f_uuid)) {
427*bbb1b6f9SApple OSS Distributions 		return;
428*bbb1b6f9SApple OSS Distributions 	}
429*bbb1b6f9SApple OSS Distributions 
430*bbb1b6f9SApple OSS Distributions 	uuid_unparse(va.f_uuid, fake_bootuuid);
431*bbb1b6f9SApple OSS Distributions }
432*bbb1b6f9SApple OSS Distributions 
433*bbb1b6f9SApple OSS Distributions /*
434*bbb1b6f9SApple OSS Distributions  * Swaps in new root filesystem based on image path.
435*bbb1b6f9SApple OSS Distributions  * Current root filesystem is removed from mount list and
436*bbb1b6f9SApple OSS Distributions  * tagged MNTK_BACKS_ROOT, MNT_ROOTFS is cleared on it, and
437*bbb1b6f9SApple OSS Distributions  * "rootvnode" is reset.  Root vnode of currentroot filesystem
438*bbb1b6f9SApple OSS Distributions  * is returned with usecount (no iocount).
439*bbb1b6f9SApple OSS Distributions  * kern.bootuuid is arranged to return the UUID of the mounted image. (If
440*bbb1b6f9SApple OSS Distributions  * we did nothing here, it would be the UUID of the image source volume.)
441*bbb1b6f9SApple OSS Distributions  */
442*bbb1b6f9SApple OSS Distributions __private_extern__ int
imageboot_mount_image(const char * root_path,int height,imageboot_type_t type)443*bbb1b6f9SApple OSS Distributions imageboot_mount_image(const char *root_path, int height, imageboot_type_t type)
444*bbb1b6f9SApple OSS Distributions {
445*bbb1b6f9SApple OSS Distributions 	dev_t           dev;
446*bbb1b6f9SApple OSS Distributions 	int             error;
447*bbb1b6f9SApple OSS Distributions 	/*
448*bbb1b6f9SApple OSS Distributions 	 * Need to stash this here since we may do a kernel_mount() on /, which will
449*bbb1b6f9SApple OSS Distributions 	 * automatically update the rootvnode global. Note that vfs_mountroot() does
450*bbb1b6f9SApple OSS Distributions 	 * not update that global, which is a bit weird.
451*bbb1b6f9SApple OSS Distributions 	 */
452*bbb1b6f9SApple OSS Distributions 	vnode_t         old_rootvnode = rootvnode;
453*bbb1b6f9SApple OSS Distributions 	vnode_t         newdp;
454*bbb1b6f9SApple OSS Distributions 	mount_t         new_rootfs;
455*bbb1b6f9SApple OSS Distributions 	boolean_t update_rootvnode = FALSE;
456*bbb1b6f9SApple OSS Distributions 
457*bbb1b6f9SApple OSS Distributions 	if (type == IMAGEBOOT_DMG) {
458*bbb1b6f9SApple OSS Distributions 		error = di_root_image(root_path, rootdevice, DEVMAXNAMESIZE, &dev);
459*bbb1b6f9SApple OSS Distributions 		if (error) {
460*bbb1b6f9SApple OSS Distributions 			panic("%s: di_root_image failed: %d", __FUNCTION__, error);
461*bbb1b6f9SApple OSS Distributions 		}
462*bbb1b6f9SApple OSS Distributions 
463*bbb1b6f9SApple OSS Distributions 		rootdev = dev;
464*bbb1b6f9SApple OSS Distributions 		mountroot = NULL;
465*bbb1b6f9SApple OSS Distributions 		printf("%s: root device 0x%x\n", __FUNCTION__, rootdev);
466*bbb1b6f9SApple OSS Distributions 		error = vfs_mountroot();
467*bbb1b6f9SApple OSS Distributions 		if (error != 0) {
468*bbb1b6f9SApple OSS Distributions 			panic("vfs_mountroot() failed.");
469*bbb1b6f9SApple OSS Distributions 		}
470*bbb1b6f9SApple OSS Distributions 
471*bbb1b6f9SApple OSS Distributions 		update_rootvnode = TRUE;
472*bbb1b6f9SApple OSS Distributions 	} else {
473*bbb1b6f9SApple OSS Distributions 		panic("invalid imageboot type: %d", type);
474*bbb1b6f9SApple OSS Distributions 	}
475*bbb1b6f9SApple OSS Distributions 
476*bbb1b6f9SApple OSS Distributions 	/*
477*bbb1b6f9SApple OSS Distributions 	 * Get the vnode for '/'.
478*bbb1b6f9SApple OSS Distributions 	 * Set fdp->fd_fd.fd_cdir to reference it.
479*bbb1b6f9SApple OSS Distributions 	 */
480*bbb1b6f9SApple OSS Distributions 	if (VFS_ROOT(TAILQ_LAST(&mountlist, mntlist), &newdp, vfs_context_kernel())) {
481*bbb1b6f9SApple OSS Distributions 		panic("%s: cannot find root vnode", __FUNCTION__);
482*bbb1b6f9SApple OSS Distributions 	}
483*bbb1b6f9SApple OSS Distributions 	DBG_TRACE("%s: old root fsname: %s\n", __FUNCTION__, old_rootvnode->v_mount->mnt_vtable->vfc_name);
484*bbb1b6f9SApple OSS Distributions 
485*bbb1b6f9SApple OSS Distributions 	if (old_rootvnode != NULL) {
486*bbb1b6f9SApple OSS Distributions 		/* remember the old rootvnode, but remove it from mountlist */
487*bbb1b6f9SApple OSS Distributions 		mount_t old_rootfs = old_rootvnode->v_mount;
488*bbb1b6f9SApple OSS Distributions 
489*bbb1b6f9SApple OSS Distributions 		mount_list_remove(old_rootfs);
490*bbb1b6f9SApple OSS Distributions 		mount_lock(old_rootfs);
491*bbb1b6f9SApple OSS Distributions 		old_rootfs->mnt_kern_flag |= MNTK_BACKS_ROOT;
492*bbb1b6f9SApple OSS Distributions 		old_rootfs->mnt_flag &= ~MNT_ROOTFS;
493*bbb1b6f9SApple OSS Distributions 		mount_unlock(old_rootfs);
494*bbb1b6f9SApple OSS Distributions 	}
495*bbb1b6f9SApple OSS Distributions 
496*bbb1b6f9SApple OSS Distributions 	vnode_ref(newdp);
497*bbb1b6f9SApple OSS Distributions 	vnode_put(newdp);
498*bbb1b6f9SApple OSS Distributions 
499*bbb1b6f9SApple OSS Distributions 	lck_rw_lock_exclusive(&rootvnode_rw_lock);
500*bbb1b6f9SApple OSS Distributions 	/* switch to the new rootvnode */
501*bbb1b6f9SApple OSS Distributions 	if (update_rootvnode) {
502*bbb1b6f9SApple OSS Distributions 		rootvnode = newdp;
503*bbb1b6f9SApple OSS Distributions 		set_fake_bootuuid(rootvnode->v_mount);
504*bbb1b6f9SApple OSS Distributions 	}
505*bbb1b6f9SApple OSS Distributions 
506*bbb1b6f9SApple OSS Distributions 	new_rootfs = rootvnode->v_mount;
507*bbb1b6f9SApple OSS Distributions 	mount_lock(new_rootfs);
508*bbb1b6f9SApple OSS Distributions 	new_rootfs->mnt_flag |= MNT_ROOTFS;
509*bbb1b6f9SApple OSS Distributions 	mount_unlock(new_rootfs);
510*bbb1b6f9SApple OSS Distributions 
511*bbb1b6f9SApple OSS Distributions 	kernproc->p_fd.fd_cdir = newdp;
512*bbb1b6f9SApple OSS Distributions 	lck_rw_unlock_exclusive(&rootvnode_rw_lock);
513*bbb1b6f9SApple OSS Distributions 
514*bbb1b6f9SApple OSS Distributions 	DBG_TRACE("%s: root switched\n", __FUNCTION__);
515*bbb1b6f9SApple OSS Distributions 
516*bbb1b6f9SApple OSS Distributions 	if (old_rootvnode != NULL) {
517*bbb1b6f9SApple OSS Distributions #ifdef CONFIG_IMGSRC_ACCESS
518*bbb1b6f9SApple OSS Distributions 		if (height >= 0) {
519*bbb1b6f9SApple OSS Distributions 			imgsrc_rootvnodes[height] = old_rootvnode;
520*bbb1b6f9SApple OSS Distributions 		} else {
521*bbb1b6f9SApple OSS Distributions 			vnode_get_and_drop_always(old_rootvnode);
522*bbb1b6f9SApple OSS Distributions 		}
523*bbb1b6f9SApple OSS Distributions #else
524*bbb1b6f9SApple OSS Distributions #pragma unused(height)
525*bbb1b6f9SApple OSS Distributions 		vnode_get_and_drop_always(old_rootvnode);
526*bbb1b6f9SApple OSS Distributions #endif /* CONFIG_IMGSRC_ACCESS */
527*bbb1b6f9SApple OSS Distributions 	}
528*bbb1b6f9SApple OSS Distributions 	return 0;
529*bbb1b6f9SApple OSS Distributions }
530*bbb1b6f9SApple OSS Distributions 
531*bbb1b6f9SApple OSS Distributions /*
532*bbb1b6f9SApple OSS Distributions  * Return a memory object for given file path.
533*bbb1b6f9SApple OSS Distributions  * Also returns a vnode reference for the given file path.
534*bbb1b6f9SApple OSS Distributions  */
535*bbb1b6f9SApple OSS Distributions void *
ubc_getobject_from_filename(const char * filename,struct vnode ** vpp,off_t * file_size)536*bbb1b6f9SApple OSS Distributions ubc_getobject_from_filename(const char *filename, struct vnode **vpp, off_t *file_size)
537*bbb1b6f9SApple OSS Distributions {
538*bbb1b6f9SApple OSS Distributions 	int err = 0;
539*bbb1b6f9SApple OSS Distributions 	struct nameidata ndp = {};
540*bbb1b6f9SApple OSS Distributions 	struct vnode *vp = NULL;
541*bbb1b6f9SApple OSS Distributions 	off_t fsize = 0;
542*bbb1b6f9SApple OSS Distributions 	vfs_context_t ctx = vfs_context_kernel();
543*bbb1b6f9SApple OSS Distributions 	void *control = NULL;
544*bbb1b6f9SApple OSS Distributions 
545*bbb1b6f9SApple OSS Distributions 	NDINIT(&ndp, LOOKUP, OP_OPEN, LOCKLEAF, UIO_SYSSPACE, CAST_USER_ADDR_T(filename), ctx);
546*bbb1b6f9SApple OSS Distributions 	if ((err = namei(&ndp)) != 0) {
547*bbb1b6f9SApple OSS Distributions 		goto errorout;
548*bbb1b6f9SApple OSS Distributions 	}
549*bbb1b6f9SApple OSS Distributions 	nameidone(&ndp);
550*bbb1b6f9SApple OSS Distributions 	vp = ndp.ni_vp;
551*bbb1b6f9SApple OSS Distributions 
552*bbb1b6f9SApple OSS Distributions 	if ((err = vnode_size(vp, &fsize, ctx)) != 0) {
553*bbb1b6f9SApple OSS Distributions 		goto errorout;
554*bbb1b6f9SApple OSS Distributions 	}
555*bbb1b6f9SApple OSS Distributions 
556*bbb1b6f9SApple OSS Distributions 	if (fsize < 0) {
557*bbb1b6f9SApple OSS Distributions 		goto errorout;
558*bbb1b6f9SApple OSS Distributions 	}
559*bbb1b6f9SApple OSS Distributions 
560*bbb1b6f9SApple OSS Distributions 	control = ubc_getobject(vp, UBC_FLAGS_NONE);
561*bbb1b6f9SApple OSS Distributions 	if (control == NULL) {
562*bbb1b6f9SApple OSS Distributions 		goto errorout;
563*bbb1b6f9SApple OSS Distributions 	}
564*bbb1b6f9SApple OSS Distributions 
565*bbb1b6f9SApple OSS Distributions 	*file_size = fsize;
566*bbb1b6f9SApple OSS Distributions 	*vpp = vp;
567*bbb1b6f9SApple OSS Distributions 	vp = NULL;
568*bbb1b6f9SApple OSS Distributions 
569*bbb1b6f9SApple OSS Distributions errorout:
570*bbb1b6f9SApple OSS Distributions 	if (vp) {
571*bbb1b6f9SApple OSS Distributions 		vnode_put(vp);
572*bbb1b6f9SApple OSS Distributions 	}
573*bbb1b6f9SApple OSS Distributions 	return control;
574*bbb1b6f9SApple OSS Distributions }
575*bbb1b6f9SApple OSS Distributions 
576*bbb1b6f9SApple OSS Distributions static int
imageboot_read_file_internal(const char * path,const off_t offset,const bool pageable,void ** bufp,size_t * bufszp,off_t * fsizep,bool no_softlimit)577*bbb1b6f9SApple OSS Distributions imageboot_read_file_internal(const char *path, const off_t offset, const bool pageable, void **bufp, size_t *bufszp, off_t *fsizep, bool no_softlimit)
578*bbb1b6f9SApple OSS Distributions {
579*bbb1b6f9SApple OSS Distributions 	int err = 0;
580*bbb1b6f9SApple OSS Distributions 	struct nameidata ndp = {};
581*bbb1b6f9SApple OSS Distributions 	struct vnode *vp = NULL;
582*bbb1b6f9SApple OSS Distributions 	struct vnode *rsrc_vp = NULL;
583*bbb1b6f9SApple OSS Distributions 	char *readbuf = NULL;
584*bbb1b6f9SApple OSS Distributions 	off_t readsize = 0;
585*bbb1b6f9SApple OSS Distributions 	off_t readoff = 0;
586*bbb1b6f9SApple OSS Distributions 	off_t fsize = 0;
587*bbb1b6f9SApple OSS Distributions 	size_t maxsize = 0;
588*bbb1b6f9SApple OSS Distributions 	char *buf = NULL;
589*bbb1b6f9SApple OSS Distributions 	bool doclose = false;
590*bbb1b6f9SApple OSS Distributions 
591*bbb1b6f9SApple OSS Distributions 	vfs_context_t ctx = vfs_context_kernel();
592*bbb1b6f9SApple OSS Distributions 	proc_t p = vfs_context_proc(ctx);
593*bbb1b6f9SApple OSS Distributions 	kauth_cred_t kerncred = vfs_context_ucred(ctx);
594*bbb1b6f9SApple OSS Distributions 
595*bbb1b6f9SApple OSS Distributions 	NDINIT(&ndp, LOOKUP, OP_OPEN, LOCKLEAF | FOLLOW, UIO_SYSSPACE, CAST_USER_ADDR_T(path), ctx);
596*bbb1b6f9SApple OSS Distributions 	if ((err = namei(&ndp)) != 0) {
597*bbb1b6f9SApple OSS Distributions 		AUTHPRNT("namei failed (%s) - %d", path, err);
598*bbb1b6f9SApple OSS Distributions 		goto out;
599*bbb1b6f9SApple OSS Distributions 	}
600*bbb1b6f9SApple OSS Distributions 	nameidone(&ndp);
601*bbb1b6f9SApple OSS Distributions 	vp = ndp.ni_vp;
602*bbb1b6f9SApple OSS Distributions 
603*bbb1b6f9SApple OSS Distributions 	if ((err = vnode_size(vp, &fsize, ctx)) != 0) {
604*bbb1b6f9SApple OSS Distributions 		AUTHPRNT("failed to get vnode size of %s - %d", path, err);
605*bbb1b6f9SApple OSS Distributions 		goto out;
606*bbb1b6f9SApple OSS Distributions 	}
607*bbb1b6f9SApple OSS Distributions 	if (fsize < 0) {
608*bbb1b6f9SApple OSS Distributions 		panic("negative file size");
609*bbb1b6f9SApple OSS Distributions 	}
610*bbb1b6f9SApple OSS Distributions 	if (offset < 0) {
611*bbb1b6f9SApple OSS Distributions 		AUTHPRNT("negative file offset");
612*bbb1b6f9SApple OSS Distributions 		err = EINVAL;
613*bbb1b6f9SApple OSS Distributions 		goto out;
614*bbb1b6f9SApple OSS Distributions 	}
615*bbb1b6f9SApple OSS Distributions 
616*bbb1b6f9SApple OSS Distributions 	if (fsizep) {
617*bbb1b6f9SApple OSS Distributions 		*fsizep = fsize;
618*bbb1b6f9SApple OSS Distributions 	}
619*bbb1b6f9SApple OSS Distributions 
620*bbb1b6f9SApple OSS Distributions 	if ((err = VNOP_OPEN(vp, FREAD, ctx)) != 0) {
621*bbb1b6f9SApple OSS Distributions 		AUTHPRNT("failed to open %s - %d", path, err);
622*bbb1b6f9SApple OSS Distributions 		goto out;
623*bbb1b6f9SApple OSS Distributions 	}
624*bbb1b6f9SApple OSS Distributions 	doclose = true;
625*bbb1b6f9SApple OSS Distributions 
626*bbb1b6f9SApple OSS Distributions 	/* cap fsize to the amount that remains after offset */
627*bbb1b6f9SApple OSS Distributions 	if (os_sub_overflow(fsize, offset, &fsize)) {
628*bbb1b6f9SApple OSS Distributions 		fsize = 0;
629*bbb1b6f9SApple OSS Distributions 	} else if (fsize < 0) {
630*bbb1b6f9SApple OSS Distributions 		fsize = 0;
631*bbb1b6f9SApple OSS Distributions 	}
632*bbb1b6f9SApple OSS Distributions 
633*bbb1b6f9SApple OSS Distributions 	/* if bufsz is non-zero, cap the read at bufsz bytes */
634*bbb1b6f9SApple OSS Distributions 	maxsize = *bufszp;
635*bbb1b6f9SApple OSS Distributions 	if (maxsize && (maxsize < (size_t)fsize)) {
636*bbb1b6f9SApple OSS Distributions 		fsize = maxsize;
637*bbb1b6f9SApple OSS Distributions 	}
638*bbb1b6f9SApple OSS Distributions 
639*bbb1b6f9SApple OSS Distributions 	/* if fsize is larger than the specified limit (presently 2.5GB) or a NVRAM-configured limit, fail */
640*bbb1b6f9SApple OSS Distributions 	maxsize = IMAGEBOOT_MAX_FILESIZE;
641*bbb1b6f9SApple OSS Distributions 	PE_parse_boot_argn("rootdmg-maxsize", &maxsize, sizeof(maxsize));
642*bbb1b6f9SApple OSS Distributions 	if (maxsize && (maxsize < (size_t)fsize)) {
643*bbb1b6f9SApple OSS Distributions 		AUTHPRNT("file is too large (%lld > %lld)", (long long) fsize, (long long) maxsize);
644*bbb1b6f9SApple OSS Distributions 		err = EFBIG;
645*bbb1b6f9SApple OSS Distributions 		goto out;
646*bbb1b6f9SApple OSS Distributions 	}
647*bbb1b6f9SApple OSS Distributions 
648*bbb1b6f9SApple OSS Distributions 	if (pageable) {
649*bbb1b6f9SApple OSS Distributions 		vm_offset_t addr = 0;
650*bbb1b6f9SApple OSS Distributions 		kma_flags_t kma_flags = 0;
651*bbb1b6f9SApple OSS Distributions 
652*bbb1b6f9SApple OSS Distributions 		kma_flags = KMA_PAGEABLE | KMA_DATA_SHARED;
653*bbb1b6f9SApple OSS Distributions 		if (no_softlimit) {
654*bbb1b6f9SApple OSS Distributions 			kma_flags |= KMA_NOSOFTLIMIT;
655*bbb1b6f9SApple OSS Distributions 		}
656*bbb1b6f9SApple OSS Distributions 
657*bbb1b6f9SApple OSS Distributions 		if (kmem_alloc(kernel_map, &addr, (vm_size_t)fsize,
658*bbb1b6f9SApple OSS Distributions 		    kma_flags, VM_KERN_MEMORY_FILE) == KERN_SUCCESS) {
659*bbb1b6f9SApple OSS Distributions 			buf = (char *)addr;
660*bbb1b6f9SApple OSS Distributions 		} else {
661*bbb1b6f9SApple OSS Distributions 			buf = NULL;
662*bbb1b6f9SApple OSS Distributions 		}
663*bbb1b6f9SApple OSS Distributions 	} else {
664*bbb1b6f9SApple OSS Distributions 		zalloc_flags_t zflags = 0;
665*bbb1b6f9SApple OSS Distributions 
666*bbb1b6f9SApple OSS Distributions 		//limit kalloc data calls to only 2GB.
667*bbb1b6f9SApple OSS Distributions 		if (fsize > IMAGEBOOT_MAX_KALLOCSIZE) {
668*bbb1b6f9SApple OSS Distributions 			AUTHPRNT("file is too large for non-pageable (%lld)", (long long) fsize);
669*bbb1b6f9SApple OSS Distributions 			err = ENOMEM;
670*bbb1b6f9SApple OSS Distributions 			goto out;
671*bbb1b6f9SApple OSS Distributions 		}
672*bbb1b6f9SApple OSS Distributions 
673*bbb1b6f9SApple OSS Distributions 		zflags = Z_WAITOK;
674*bbb1b6f9SApple OSS Distributions 		if (no_softlimit) {
675*bbb1b6f9SApple OSS Distributions 			zflags |= Z_NOSOFTLIMIT;
676*bbb1b6f9SApple OSS Distributions 		}
677*bbb1b6f9SApple OSS Distributions 
678*bbb1b6f9SApple OSS Distributions 		buf = (char *)kalloc_data((vm_size_t)fsize, zflags);
679*bbb1b6f9SApple OSS Distributions 	}
680*bbb1b6f9SApple OSS Distributions 	if (buf == NULL) {
681*bbb1b6f9SApple OSS Distributions 		err = ENOMEM;
682*bbb1b6f9SApple OSS Distributions 		goto out;
683*bbb1b6f9SApple OSS Distributions 	}
684*bbb1b6f9SApple OSS Distributions 
685*bbb1b6f9SApple OSS Distributions #if NAMEDSTREAMS
686*bbb1b6f9SApple OSS Distributions 	/* find resource fork so we can evict cached decmpfs data */
687*bbb1b6f9SApple OSS Distributions 	if (VNOP_GETNAMEDSTREAM(vp, &rsrc_vp, XATTR_RESOURCEFORK_NAME, NS_OPEN, /*flags*/ 0, ctx) == 0) {
688*bbb1b6f9SApple OSS Distributions 		vnode_ref(rsrc_vp);
689*bbb1b6f9SApple OSS Distributions 		vnode_put(rsrc_vp);
690*bbb1b6f9SApple OSS Distributions 		AUTHDBG("Found resource fork for %s", path);
691*bbb1b6f9SApple OSS Distributions 	}
692*bbb1b6f9SApple OSS Distributions #endif
693*bbb1b6f9SApple OSS Distributions 
694*bbb1b6f9SApple OSS Distributions 	/* read data in chunks to handle (fsize > INT_MAX) */
695*bbb1b6f9SApple OSS Distributions 	readbuf = buf;
696*bbb1b6f9SApple OSS Distributions 	readsize = fsize;
697*bbb1b6f9SApple OSS Distributions 	readoff = offset;
698*bbb1b6f9SApple OSS Distributions 	while (readsize > 0) {
699*bbb1b6f9SApple OSS Distributions 		const off_t chunksize_max = 16 * 1024 * 1024; /* 16 MiB */
700*bbb1b6f9SApple OSS Distributions 		const off_t chunksize = MIN(readsize, chunksize_max);
701*bbb1b6f9SApple OSS Distributions 
702*bbb1b6f9SApple OSS Distributions 		/* read next chunk, pass IO_NOCACHE to clarify our intent (even if ignored) */
703*bbb1b6f9SApple OSS Distributions 		if ((err = vn_rdwr(UIO_READ, vp, (caddr_t)readbuf, (int)chunksize, readoff, UIO_SYSSPACE, IO_NODELOCKED | IO_NOCACHE | IO_RAOFF, kerncred, /*resid*/ NULL, p)) != 0) {
704*bbb1b6f9SApple OSS Distributions 			AUTHPRNT("Cannot read %lld bytes at offset %lld from %s - %d", (long long)chunksize, (long long)readoff, path, err);
705*bbb1b6f9SApple OSS Distributions 			goto out;
706*bbb1b6f9SApple OSS Distributions 		}
707*bbb1b6f9SApple OSS Distributions 
708*bbb1b6f9SApple OSS Distributions 		/* evict cached pages so they don't accumulate during early boot */
709*bbb1b6f9SApple OSS Distributions 		ubc_msync(vp, readoff, readoff + chunksize, NULL, UBC_INVALIDATE | UBC_PUSHALL);
710*bbb1b6f9SApple OSS Distributions 
711*bbb1b6f9SApple OSS Distributions 		/* evict potentially-cached decmpfs data if we have a resource fork */
712*bbb1b6f9SApple OSS Distributions 		if (rsrc_vp != NULL) {
713*bbb1b6f9SApple OSS Distributions 			if (vnode_getwithref(rsrc_vp) == 0) {
714*bbb1b6f9SApple OSS Distributions 				ubc_msync(rsrc_vp, 0, ubc_getsize(rsrc_vp), NULL, UBC_INVALIDATE | UBC_PUSHALL);
715*bbb1b6f9SApple OSS Distributions 				vnode_put(rsrc_vp);
716*bbb1b6f9SApple OSS Distributions 			}
717*bbb1b6f9SApple OSS Distributions 		}
718*bbb1b6f9SApple OSS Distributions 
719*bbb1b6f9SApple OSS Distributions 		readbuf = VM_FAR_ADD_PTR_UNBOUNDED(readbuf, chunksize);
720*bbb1b6f9SApple OSS Distributions 		readsize -= chunksize;
721*bbb1b6f9SApple OSS Distributions 		readoff += chunksize;
722*bbb1b6f9SApple OSS Distributions 	}
723*bbb1b6f9SApple OSS Distributions 
724*bbb1b6f9SApple OSS Distributions out:
725*bbb1b6f9SApple OSS Distributions 	if (doclose) {
726*bbb1b6f9SApple OSS Distributions 		VNOP_CLOSE(vp, FREAD, ctx);
727*bbb1b6f9SApple OSS Distributions 	}
728*bbb1b6f9SApple OSS Distributions 	if (rsrc_vp) {
729*bbb1b6f9SApple OSS Distributions 		vnode_rele(rsrc_vp);
730*bbb1b6f9SApple OSS Distributions 		rsrc_vp = NULL;
731*bbb1b6f9SApple OSS Distributions 	}
732*bbb1b6f9SApple OSS Distributions 	if (vp) {
733*bbb1b6f9SApple OSS Distributions 		vnode_put(vp);
734*bbb1b6f9SApple OSS Distributions 		vp = NULL;
735*bbb1b6f9SApple OSS Distributions 	}
736*bbb1b6f9SApple OSS Distributions 
737*bbb1b6f9SApple OSS Distributions 	if (err) {
738*bbb1b6f9SApple OSS Distributions 		if (buf == NULL) {
739*bbb1b6f9SApple OSS Distributions 			/* nothing to free */
740*bbb1b6f9SApple OSS Distributions 		} else if (pageable) {
741*bbb1b6f9SApple OSS Distributions 			kmem_free(kernel_map, (vm_offset_t)buf, (vm_size_t)fsize);
742*bbb1b6f9SApple OSS Distributions 		} else {
743*bbb1b6f9SApple OSS Distributions 			kfree_data(buf, (vm_size_t)fsize);
744*bbb1b6f9SApple OSS Distributions 		}
745*bbb1b6f9SApple OSS Distributions 	} else {
746*bbb1b6f9SApple OSS Distributions 		*bufp = buf;
747*bbb1b6f9SApple OSS Distributions 		*bufszp = (size_t)fsize;
748*bbb1b6f9SApple OSS Distributions 	}
749*bbb1b6f9SApple OSS Distributions 
750*bbb1b6f9SApple OSS Distributions 	return err;
751*bbb1b6f9SApple OSS Distributions }
752*bbb1b6f9SApple OSS Distributions 
753*bbb1b6f9SApple OSS Distributions int
imageboot_read_file_pageable(const char * path,void ** bufp,size_t * bufszp,bool no_softlimit)754*bbb1b6f9SApple OSS Distributions imageboot_read_file_pageable(const char *path, void **bufp, size_t *bufszp, bool no_softlimit)
755*bbb1b6f9SApple OSS Distributions {
756*bbb1b6f9SApple OSS Distributions 	return imageboot_read_file_internal(path, 0, true, bufp, bufszp, NULL, no_softlimit);
757*bbb1b6f9SApple OSS Distributions }
758*bbb1b6f9SApple OSS Distributions 
759*bbb1b6f9SApple OSS Distributions int
imageboot_read_file_from_offset(const char * path,const off_t offset,void ** bufp,size_t * bufszp)760*bbb1b6f9SApple OSS Distributions imageboot_read_file_from_offset(const char *path, const off_t offset, void **bufp, size_t *bufszp)
761*bbb1b6f9SApple OSS Distributions {
762*bbb1b6f9SApple OSS Distributions 	return imageboot_read_file_internal(path, offset, false, bufp, bufszp, NULL, /* no_softlimit */ false);
763*bbb1b6f9SApple OSS Distributions }
764*bbb1b6f9SApple OSS Distributions 
765*bbb1b6f9SApple OSS Distributions int
imageboot_read_file(const char * path,void ** bufp,size_t * bufszp,off_t * fsizep)766*bbb1b6f9SApple OSS Distributions imageboot_read_file(const char *path, void **bufp, size_t *bufszp, off_t *fsizep)
767*bbb1b6f9SApple OSS Distributions {
768*bbb1b6f9SApple OSS Distributions 	return imageboot_read_file_internal(path, 0, false, bufp, bufszp, fsizep, /* no_softlimit */ false);
769*bbb1b6f9SApple OSS Distributions }
770*bbb1b6f9SApple OSS Distributions 
771*bbb1b6f9SApple OSS Distributions #if CONFIG_IMAGEBOOT_IMG4 || CONFIG_IMAGEBOOT_CHUNKLIST
772*bbb1b6f9SApple OSS Distributions vnode_t
imgboot_get_image_file(const char * path,off_t * fsize,int * errp)773*bbb1b6f9SApple OSS Distributions imgboot_get_image_file(const char *path, off_t *fsize, int *errp)
774*bbb1b6f9SApple OSS Distributions {
775*bbb1b6f9SApple OSS Distributions 	struct nameidata ndp = {};
776*bbb1b6f9SApple OSS Distributions 	vnode_t vp = NULL;
777*bbb1b6f9SApple OSS Distributions 	vfs_context_t ctx = vfs_context_kernel();
778*bbb1b6f9SApple OSS Distributions 	int err;
779*bbb1b6f9SApple OSS Distributions 
780*bbb1b6f9SApple OSS Distributions 	NDINIT(&ndp, LOOKUP, OP_OPEN, LOCKLEAF, UIO_SYSSPACE, CAST_USER_ADDR_T(path), ctx);
781*bbb1b6f9SApple OSS Distributions 	if ((err = namei(&ndp)) != 0) {
782*bbb1b6f9SApple OSS Distributions 		AUTHPRNT("Cannot find %s - error %d", path, err);
783*bbb1b6f9SApple OSS Distributions 	} else {
784*bbb1b6f9SApple OSS Distributions 		nameidone(&ndp);
785*bbb1b6f9SApple OSS Distributions 		vp = ndp.ni_vp;
786*bbb1b6f9SApple OSS Distributions 
787*bbb1b6f9SApple OSS Distributions 		if (vp->v_type != VREG) {
788*bbb1b6f9SApple OSS Distributions 			err = EINVAL;
789*bbb1b6f9SApple OSS Distributions 			AUTHPRNT("%s it not a regular file", path);
790*bbb1b6f9SApple OSS Distributions 		} else if (fsize) {
791*bbb1b6f9SApple OSS Distributions 			if ((err = vnode_size(vp, fsize, ctx)) != 0) {
792*bbb1b6f9SApple OSS Distributions 				AUTHPRNT("Cannot get file size of %s - error %d", path, err);
793*bbb1b6f9SApple OSS Distributions 			}
794*bbb1b6f9SApple OSS Distributions 		}
795*bbb1b6f9SApple OSS Distributions 	}
796*bbb1b6f9SApple OSS Distributions 
797*bbb1b6f9SApple OSS Distributions 	if (err) {
798*bbb1b6f9SApple OSS Distributions 		if (vp) {
799*bbb1b6f9SApple OSS Distributions 			vnode_put(vp);
800*bbb1b6f9SApple OSS Distributions 		}
801*bbb1b6f9SApple OSS Distributions 		*errp = err;
802*bbb1b6f9SApple OSS Distributions 		vp = NULL;
803*bbb1b6f9SApple OSS Distributions 	}
804*bbb1b6f9SApple OSS Distributions 	return vp;
805*bbb1b6f9SApple OSS Distributions }
806*bbb1b6f9SApple OSS Distributions #endif /* CONFIG_IMAGEBOOT_CHUNKLIST || CONFIG_IMAGEBOOT_CHUNKLIST */
807*bbb1b6f9SApple OSS Distributions 
808*bbb1b6f9SApple OSS Distributions #if CONFIG_IMAGEBOOT_IMG4
809*bbb1b6f9SApple OSS Distributions 
810*bbb1b6f9SApple OSS Distributions #define APTICKET_NAME "apticket.der"
811*bbb1b6f9SApple OSS Distributions 
812*bbb1b6f9SApple OSS Distributions static char *
imgboot_get_apticket_path(const char * rootpath,size_t * sz)813*bbb1b6f9SApple OSS Distributions imgboot_get_apticket_path(const char *rootpath, size_t *sz)
814*bbb1b6f9SApple OSS Distributions {
815*bbb1b6f9SApple OSS Distributions 	size_t plen = strlen(rootpath) + sizeof(APTICKET_NAME) + 1;
816*bbb1b6f9SApple OSS Distributions 	char *path = (char *)kalloc_data(plen, Z_WAITOK);
817*bbb1b6f9SApple OSS Distributions 
818*bbb1b6f9SApple OSS Distributions 	if (path) {
819*bbb1b6f9SApple OSS Distributions 		char *slash;
820*bbb1b6f9SApple OSS Distributions 
821*bbb1b6f9SApple OSS Distributions 		strlcpy(path, rootpath, plen);
822*bbb1b6f9SApple OSS Distributions 		slash = strrchr(path, '/');
823*bbb1b6f9SApple OSS Distributions 		if (slash == NULL) {
824*bbb1b6f9SApple OSS Distributions 			slash = path;
825*bbb1b6f9SApple OSS Distributions 		} else {
826*bbb1b6f9SApple OSS Distributions 			slash++;
827*bbb1b6f9SApple OSS Distributions 		}
828*bbb1b6f9SApple OSS Distributions 		strlcpy(slash, APTICKET_NAME, sizeof(APTICKET_NAME) + 1);
829*bbb1b6f9SApple OSS Distributions 	}
830*bbb1b6f9SApple OSS Distributions 
831*bbb1b6f9SApple OSS Distributions 	*sz = plen;
832*bbb1b6f9SApple OSS Distributions 	return path;
833*bbb1b6f9SApple OSS Distributions }
834*bbb1b6f9SApple OSS Distributions 
835*bbb1b6f9SApple OSS Distributions static int
authenticate_root_with_img4(const char * rootpath)836*bbb1b6f9SApple OSS Distributions authenticate_root_with_img4(const char *rootpath)
837*bbb1b6f9SApple OSS Distributions {
838*bbb1b6f9SApple OSS Distributions 	errno_t rv;
839*bbb1b6f9SApple OSS Distributions 	vnode_t vp = NULLVP;
840*bbb1b6f9SApple OSS Distributions 	size_t ticket_pathsz = 0;
841*bbb1b6f9SApple OSS Distributions 	char *ticket_path;
842*bbb1b6f9SApple OSS Distributions 	img4_buff_t tck = IMG4_BUFF_INIT;
843*bbb1b6f9SApple OSS Distributions 	img4_firmware_execution_context_t exec = {
844*bbb1b6f9SApple OSS Distributions 		.i4fex_version = IMG4_FIRMWARE_EXECUTION_CONTEXT_STRUCT_VERSION,
845*bbb1b6f9SApple OSS Distributions 		.i4fex_execute = NULL,
846*bbb1b6f9SApple OSS Distributions 		.i4fex_context = NULL,
847*bbb1b6f9SApple OSS Distributions 	};
848*bbb1b6f9SApple OSS Distributions 	img4_firmware_t fw = NULL;
849*bbb1b6f9SApple OSS Distributions 	img4_firmware_flags_t fw_flags = IMG4_FIRMWARE_FLAG_BARE |
850*bbb1b6f9SApple OSS Distributions 	    IMG4_FIRMWARE_FLAG_SUBSEQUENT_STAGE;
851*bbb1b6f9SApple OSS Distributions 
852*bbb1b6f9SApple OSS Distributions 	DBG_TRACE("Check %s\n", rootpath);
853*bbb1b6f9SApple OSS Distributions 
854*bbb1b6f9SApple OSS Distributions 	ticket_path = imgboot_get_apticket_path(rootpath, &ticket_pathsz);
855*bbb1b6f9SApple OSS Distributions 	if (ticket_path == NULL) {
856*bbb1b6f9SApple OSS Distributions 		AUTHPRNT("Cannot construct ticket path - out of memory");
857*bbb1b6f9SApple OSS Distributions 		return ENOMEM;
858*bbb1b6f9SApple OSS Distributions 	}
859*bbb1b6f9SApple OSS Distributions 
860*bbb1b6f9SApple OSS Distributions 	rv = imageboot_read_file(ticket_path, (void **)&tck.i4b_bytes, &tck.i4b_len, NULL);
861*bbb1b6f9SApple OSS Distributions 	if (rv) {
862*bbb1b6f9SApple OSS Distributions 		AUTHPRNT("Cannot get a ticket from %s - %d\n", ticket_path, rv);
863*bbb1b6f9SApple OSS Distributions 		goto out_with_ticket_path;
864*bbb1b6f9SApple OSS Distributions 	}
865*bbb1b6f9SApple OSS Distributions 
866*bbb1b6f9SApple OSS Distributions 	DBG_TRACE("Got %lu bytes of manifest from %s\n", tck.i4b_len, ticket_path);
867*bbb1b6f9SApple OSS Distributions 
868*bbb1b6f9SApple OSS Distributions 	vp = imgboot_get_image_file(rootpath, NULL, &rv);
869*bbb1b6f9SApple OSS Distributions 	if (vp == NULL) {
870*bbb1b6f9SApple OSS Distributions 		/* Error message had been printed already */
871*bbb1b6f9SApple OSS Distributions 		rv = EIO;
872*bbb1b6f9SApple OSS Distributions 		goto out_with_ticket_bytes;
873*bbb1b6f9SApple OSS Distributions 	}
874*bbb1b6f9SApple OSS Distributions 
875*bbb1b6f9SApple OSS Distributions 	fw = img4_firmware_new_from_vnode_4xnu(IMG4_RUNTIME_DEFAULT, &exec, 'rosi',
876*bbb1b6f9SApple OSS Distributions 	    vp, fw_flags);
877*bbb1b6f9SApple OSS Distributions 	if (!fw) {
878*bbb1b6f9SApple OSS Distributions 		AUTHPRNT("Could not allocate new firmware");
879*bbb1b6f9SApple OSS Distributions 		rv = ENOMEM;
880*bbb1b6f9SApple OSS Distributions 		goto out_with_ticket_bytes;
881*bbb1b6f9SApple OSS Distributions 	}
882*bbb1b6f9SApple OSS Distributions 
883*bbb1b6f9SApple OSS Distributions 	img4_firmware_attach_manifest(fw, &tck);
884*bbb1b6f9SApple OSS Distributions 	rv = img4_firmware_evaluate(fw, img4_chip_select_personalized_ap(), NULL);
885*bbb1b6f9SApple OSS Distributions 
886*bbb1b6f9SApple OSS Distributions out_with_ticket_bytes:
887*bbb1b6f9SApple OSS Distributions 	kfree_data(tck.i4b_bytes, tck.i4b_len);
888*bbb1b6f9SApple OSS Distributions out_with_ticket_path:
889*bbb1b6f9SApple OSS Distributions 	kfree_data(ticket_path, ticket_pathsz);
890*bbb1b6f9SApple OSS Distributions 
891*bbb1b6f9SApple OSS Distributions 	img4_firmware_destroy(&fw);
892*bbb1b6f9SApple OSS Distributions 
893*bbb1b6f9SApple OSS Distributions 	if (vp) {
894*bbb1b6f9SApple OSS Distributions 		vnode_put(vp);
895*bbb1b6f9SApple OSS Distributions 	}
896*bbb1b6f9SApple OSS Distributions 	return rv;
897*bbb1b6f9SApple OSS Distributions }
898*bbb1b6f9SApple OSS Distributions #endif /* CONFIG_IMAGEBOOT_IMG4 */
899*bbb1b6f9SApple OSS Distributions 
900*bbb1b6f9SApple OSS Distributions 
901*bbb1b6f9SApple OSS Distributions /*
902*bbb1b6f9SApple OSS Distributions  * Attach the image at 'path' as a ramdisk and mount it as our new rootfs.
903*bbb1b6f9SApple OSS Distributions  * All existing mounts are first umounted.
904*bbb1b6f9SApple OSS Distributions  */
905*bbb1b6f9SApple OSS Distributions static int
imageboot_mount_ramdisk(const char * path)906*bbb1b6f9SApple OSS Distributions imageboot_mount_ramdisk(const char *path)
907*bbb1b6f9SApple OSS Distributions {
908*bbb1b6f9SApple OSS Distributions 	int err = 0;
909*bbb1b6f9SApple OSS Distributions 	size_t bufsz = 0;
910*bbb1b6f9SApple OSS Distributions 	void *buf = NULL;
911*bbb1b6f9SApple OSS Distributions 	dev_t dev;
912*bbb1b6f9SApple OSS Distributions 	vnode_t newdp;
913*bbb1b6f9SApple OSS Distributions 	vnode_t tvp;
914*bbb1b6f9SApple OSS Distributions 	mount_t new_rootfs;
915*bbb1b6f9SApple OSS Distributions 
916*bbb1b6f9SApple OSS Distributions 	/*
917*bbb1b6f9SApple OSS Distributions 	 * Read our target image from disk
918*bbb1b6f9SApple OSS Distributions 	 *
919*bbb1b6f9SApple OSS Distributions 	 * We override the allocator soft-limit in order to allow booting large RAM
920*bbb1b6f9SApple OSS Distributions 	 * disks. As a consequence, we are responsible for manipulating the
921*bbb1b6f9SApple OSS Distributions 	 * buffer only through vm_far safe APIs.
922*bbb1b6f9SApple OSS Distributions 	 */
923*bbb1b6f9SApple OSS Distributions 	err = imageboot_read_file_pageable(path, &buf, &bufsz, /* no_softlimit */ true);
924*bbb1b6f9SApple OSS Distributions 	if (err) {
925*bbb1b6f9SApple OSS Distributions 		printf("%s: failed: imageboot_read_file_pageable() = %d\n", __func__, err);
926*bbb1b6f9SApple OSS Distributions 		goto out;
927*bbb1b6f9SApple OSS Distributions 	}
928*bbb1b6f9SApple OSS Distributions 	DBG_TRACE("%s: read '%s' sz = %lu\n", __func__, path, bufsz);
929*bbb1b6f9SApple OSS Distributions 
930*bbb1b6f9SApple OSS Distributions #if CONFIG_IMGSRC_ACCESS
931*bbb1b6f9SApple OSS Distributions 	/* Re-add all root mounts to the mount list in the correct order... */
932*bbb1b6f9SApple OSS Distributions 	mount_list_remove(rootvnode->v_mount);
933*bbb1b6f9SApple OSS Distributions 	for (int i = 0; i < MAX_IMAGEBOOT_NESTING; i++) {
934*bbb1b6f9SApple OSS Distributions 		struct vnode *vn = imgsrc_rootvnodes[i];
935*bbb1b6f9SApple OSS Distributions 		if (vn) {
936*bbb1b6f9SApple OSS Distributions 			vnode_getalways(vn);
937*bbb1b6f9SApple OSS Distributions 			imgsrc_rootvnodes[i] = NULLVP;
938*bbb1b6f9SApple OSS Distributions 
939*bbb1b6f9SApple OSS Distributions 			mount_t mnt = vn->v_mount;
940*bbb1b6f9SApple OSS Distributions 			mount_lock(mnt);
941*bbb1b6f9SApple OSS Distributions 			mnt->mnt_flag |= MNT_ROOTFS;
942*bbb1b6f9SApple OSS Distributions 			mount_list_add(mnt);
943*bbb1b6f9SApple OSS Distributions 			mount_unlock(mnt);
944*bbb1b6f9SApple OSS Distributions 
945*bbb1b6f9SApple OSS Distributions 			vnode_rele(vn);
946*bbb1b6f9SApple OSS Distributions 			vnode_put(vn);
947*bbb1b6f9SApple OSS Distributions 		}
948*bbb1b6f9SApple OSS Distributions 	}
949*bbb1b6f9SApple OSS Distributions 	mount_list_add(rootvnode->v_mount);
950*bbb1b6f9SApple OSS Distributions #endif
951*bbb1b6f9SApple OSS Distributions 
952*bbb1b6f9SApple OSS Distributions 	/* ... and unmount everything */
953*bbb1b6f9SApple OSS Distributions 	vfs_unmountall(FALSE);
954*bbb1b6f9SApple OSS Distributions 
955*bbb1b6f9SApple OSS Distributions 	lck_rw_lock_exclusive(&rootvnode_rw_lock);
956*bbb1b6f9SApple OSS Distributions 	kernproc->p_fd.fd_cdir = NULL;
957*bbb1b6f9SApple OSS Distributions 	tvp = rootvnode;
958*bbb1b6f9SApple OSS Distributions 	rootvnode = NULL;
959*bbb1b6f9SApple OSS Distributions 	rootvp = NULLVP;
960*bbb1b6f9SApple OSS Distributions 	rootdev = NODEV;
961*bbb1b6f9SApple OSS Distributions 	lck_rw_unlock_exclusive(&rootvnode_rw_lock);
962*bbb1b6f9SApple OSS Distributions 	vnode_get_and_drop_always(tvp);
963*bbb1b6f9SApple OSS Distributions 
964*bbb1b6f9SApple OSS Distributions 	/* Attach the ramfs image ... */
965*bbb1b6f9SApple OSS Distributions 	err = di_root_ramfile_buf(buf, bufsz, rootdevice, DEVMAXNAMESIZE, &dev);
966*bbb1b6f9SApple OSS Distributions 	if (err) {
967*bbb1b6f9SApple OSS Distributions 		printf("%s: failed: di_root_ramfile_buf() = %d\n", __func__, err);
968*bbb1b6f9SApple OSS Distributions 		goto out;
969*bbb1b6f9SApple OSS Distributions 	}
970*bbb1b6f9SApple OSS Distributions 
971*bbb1b6f9SApple OSS Distributions 	/* ... and mount it */
972*bbb1b6f9SApple OSS Distributions 	rootdev = dev;
973*bbb1b6f9SApple OSS Distributions 	mountroot = NULL;
974*bbb1b6f9SApple OSS Distributions 	err = vfs_mountroot();
975*bbb1b6f9SApple OSS Distributions 	if (err) {
976*bbb1b6f9SApple OSS Distributions 		printf("%s: failed: vfs_mountroot() = %d\n", __func__, err);
977*bbb1b6f9SApple OSS Distributions 		goto out;
978*bbb1b6f9SApple OSS Distributions 	}
979*bbb1b6f9SApple OSS Distributions 
980*bbb1b6f9SApple OSS Distributions 	/* Switch to new root vnode */
981*bbb1b6f9SApple OSS Distributions 	if (VFS_ROOT(TAILQ_LAST(&mountlist, mntlist), &newdp, vfs_context_kernel())) {
982*bbb1b6f9SApple OSS Distributions 		panic("%s: cannot find root vnode", __func__);
983*bbb1b6f9SApple OSS Distributions 	}
984*bbb1b6f9SApple OSS Distributions 	vnode_ref(newdp);
985*bbb1b6f9SApple OSS Distributions 
986*bbb1b6f9SApple OSS Distributions 	lck_rw_lock_exclusive(&rootvnode_rw_lock);
987*bbb1b6f9SApple OSS Distributions 	rootvnode = newdp;
988*bbb1b6f9SApple OSS Distributions 	rootvnode->v_flag |= VROOT;
989*bbb1b6f9SApple OSS Distributions 	new_rootfs = rootvnode->v_mount;
990*bbb1b6f9SApple OSS Distributions 	mount_lock(new_rootfs);
991*bbb1b6f9SApple OSS Distributions 	new_rootfs->mnt_flag |= MNT_ROOTFS;
992*bbb1b6f9SApple OSS Distributions 	mount_unlock(new_rootfs);
993*bbb1b6f9SApple OSS Distributions 
994*bbb1b6f9SApple OSS Distributions 	set_fake_bootuuid(new_rootfs);
995*bbb1b6f9SApple OSS Distributions 
996*bbb1b6f9SApple OSS Distributions 	kernproc->p_fd.fd_cdir = newdp;
997*bbb1b6f9SApple OSS Distributions 	lck_rw_unlock_exclusive(&rootvnode_rw_lock);
998*bbb1b6f9SApple OSS Distributions 
999*bbb1b6f9SApple OSS Distributions 	vnode_put(newdp);
1000*bbb1b6f9SApple OSS Distributions 
1001*bbb1b6f9SApple OSS Distributions 	DBG_TRACE("%s: root switched\n", __func__);
1002*bbb1b6f9SApple OSS Distributions 
1003*bbb1b6f9SApple OSS Distributions out:
1004*bbb1b6f9SApple OSS Distributions 	if (err && (buf != NULL)) {
1005*bbb1b6f9SApple OSS Distributions 		kmem_free(kernel_map, (vm_offset_t)buf, (vm_size_t)bufsz);
1006*bbb1b6f9SApple OSS Distributions 	}
1007*bbb1b6f9SApple OSS Distributions 	return err;
1008*bbb1b6f9SApple OSS Distributions }
1009*bbb1b6f9SApple OSS Distributions 
1010*bbb1b6f9SApple OSS Distributions /*
1011*bbb1b6f9SApple OSS Distributions  * If the path is in <file://> URL format then we allocate memory and decode it,
1012*bbb1b6f9SApple OSS Distributions  * otherwise return the same pointer.
1013*bbb1b6f9SApple OSS Distributions  *
1014*bbb1b6f9SApple OSS Distributions  * Caller is expected to check if the pointers are different.
1015*bbb1b6f9SApple OSS Distributions  */
1016*bbb1b6f9SApple OSS Distributions static char *
url_to_path(char * url_path,size_t * sz)1017*bbb1b6f9SApple OSS Distributions url_to_path(char *url_path, size_t *sz)
1018*bbb1b6f9SApple OSS Distributions {
1019*bbb1b6f9SApple OSS Distributions 	char *path = url_path;
1020*bbb1b6f9SApple OSS Distributions 	size_t len = strlen(kIBFilePrefix);
1021*bbb1b6f9SApple OSS Distributions 
1022*bbb1b6f9SApple OSS Distributions 	if (strncmp(kIBFilePrefix, url_path, len) == 0) {
1023*bbb1b6f9SApple OSS Distributions 		/* its a URL - remove the file:// prefix and percent-decode */
1024*bbb1b6f9SApple OSS Distributions 		url_path += len;
1025*bbb1b6f9SApple OSS Distributions 
1026*bbb1b6f9SApple OSS Distributions 		len = strlen(url_path);
1027*bbb1b6f9SApple OSS Distributions 		if (len) {
1028*bbb1b6f9SApple OSS Distributions 			/* Make a copy of the path to URL-decode */
1029*bbb1b6f9SApple OSS Distributions 			path = (char *)kalloc_data(len + 1, Z_WAITOK);
1030*bbb1b6f9SApple OSS Distributions 			if (path == NULL) {
1031*bbb1b6f9SApple OSS Distributions 				panic("imageboot path allocation failed - cannot allocate %d bytes", (int)len);
1032*bbb1b6f9SApple OSS Distributions 			}
1033*bbb1b6f9SApple OSS Distributions 
1034*bbb1b6f9SApple OSS Distributions 			strlcpy(path, url_path, len + 1);
1035*bbb1b6f9SApple OSS Distributions 			*sz = len + 1;
1036*bbb1b6f9SApple OSS Distributions 			url_decode(path);
1037*bbb1b6f9SApple OSS Distributions 		} else {
1038*bbb1b6f9SApple OSS Distributions 			panic("Bogus imageboot path URL - missing path");
1039*bbb1b6f9SApple OSS Distributions 		}
1040*bbb1b6f9SApple OSS Distributions 
1041*bbb1b6f9SApple OSS Distributions 		DBG_TRACE("%s: root image URL <%s> becomes %s\n", __func__, url_path, path);
1042*bbb1b6f9SApple OSS Distributions 	}
1043*bbb1b6f9SApple OSS Distributions 
1044*bbb1b6f9SApple OSS Distributions 	return path;
1045*bbb1b6f9SApple OSS Distributions }
1046*bbb1b6f9SApple OSS Distributions 
1047*bbb1b6f9SApple OSS Distributions static boolean_t
imageboot_setup_new(imageboot_type_t type)1048*bbb1b6f9SApple OSS Distributions imageboot_setup_new(imageboot_type_t type)
1049*bbb1b6f9SApple OSS Distributions {
1050*bbb1b6f9SApple OSS Distributions 	int error;
1051*bbb1b6f9SApple OSS Distributions 	char *root_path = NULL;
1052*bbb1b6f9SApple OSS Distributions 	int height = 0;
1053*bbb1b6f9SApple OSS Distributions 	boolean_t done = FALSE;
1054*bbb1b6f9SApple OSS Distributions 	boolean_t auth_root = TRUE;
1055*bbb1b6f9SApple OSS Distributions 	boolean_t ramdisk_root = FALSE;
1056*bbb1b6f9SApple OSS Distributions 
1057*bbb1b6f9SApple OSS Distributions 	root_path = zalloc(ZV_NAMEI);
1058*bbb1b6f9SApple OSS Distributions 	assert(root_path != NULL);
1059*bbb1b6f9SApple OSS Distributions 
1060*bbb1b6f9SApple OSS Distributions 	unsigned imgboot_arg;
1061*bbb1b6f9SApple OSS Distributions 	if (PE_parse_boot_argn("-rootdmg-ramdisk", &imgboot_arg, sizeof(imgboot_arg))) {
1062*bbb1b6f9SApple OSS Distributions 		ramdisk_root = TRUE;
1063*bbb1b6f9SApple OSS Distributions 	}
1064*bbb1b6f9SApple OSS Distributions 
1065*bbb1b6f9SApple OSS Distributions 	if (PE_parse_boot_argn(IMAGEBOOT_CONTAINER_ARG, root_path, MAXPATHLEN) == TRUE) {
1066*bbb1b6f9SApple OSS Distributions 		printf("%s: container image url is %s\n", __FUNCTION__, root_path);
1067*bbb1b6f9SApple OSS Distributions 		error = imageboot_mount_image(root_path, height, type);
1068*bbb1b6f9SApple OSS Distributions 		if (error != 0) {
1069*bbb1b6f9SApple OSS Distributions 			panic("Failed to mount container image.");
1070*bbb1b6f9SApple OSS Distributions 		}
1071*bbb1b6f9SApple OSS Distributions 
1072*bbb1b6f9SApple OSS Distributions 		height++;
1073*bbb1b6f9SApple OSS Distributions 	}
1074*bbb1b6f9SApple OSS Distributions 
1075*bbb1b6f9SApple OSS Distributions 	if (PE_parse_boot_argn(IMAGEBOOT_AUTHROOT_ARG, root_path, MAXPATHLEN) == FALSE &&
1076*bbb1b6f9SApple OSS Distributions 	    PE_parse_boot_argn(IMAGEBOOT_ROOT_ARG, root_path, MAXPATHLEN) == FALSE) {
1077*bbb1b6f9SApple OSS Distributions 		if (height > 0) {
1078*bbb1b6f9SApple OSS Distributions 			panic("%s specified without %s or %s?", IMAGEBOOT_CONTAINER_ARG, IMAGEBOOT_AUTHROOT_ARG, IMAGEBOOT_ROOT_ARG);
1079*bbb1b6f9SApple OSS Distributions 		}
1080*bbb1b6f9SApple OSS Distributions 		goto out;
1081*bbb1b6f9SApple OSS Distributions 	}
1082*bbb1b6f9SApple OSS Distributions 
1083*bbb1b6f9SApple OSS Distributions 	printf("%s: root image URL is '%s'\n", __func__, root_path);
1084*bbb1b6f9SApple OSS Distributions 
1085*bbb1b6f9SApple OSS Distributions 	/* Make a copy of the path to URL-decode */
1086*bbb1b6f9SApple OSS Distributions 	size_t pathsz;
1087*bbb1b6f9SApple OSS Distributions 	char *path = url_to_path(root_path, &pathsz);
1088*bbb1b6f9SApple OSS Distributions 	assert(path);
1089*bbb1b6f9SApple OSS Distributions 
1090*bbb1b6f9SApple OSS Distributions #if CONFIG_IMAGEBOOT_CHUNKLIST
1091*bbb1b6f9SApple OSS Distributions 	if (auth_root) {
1092*bbb1b6f9SApple OSS Distributions 		/*
1093*bbb1b6f9SApple OSS Distributions 		 * This updates auth_root to reflect whether chunklist was
1094*bbb1b6f9SApple OSS Distributions 		 * actually enforced. In effect, this clears auth_root if
1095*bbb1b6f9SApple OSS Distributions 		 * CSR_ALLOW_ANY_RECOVERY_OS allowed an invalid image.
1096*bbb1b6f9SApple OSS Distributions 		 */
1097*bbb1b6f9SApple OSS Distributions 		AUTHDBG("authenticating root image at %s", path);
1098*bbb1b6f9SApple OSS Distributions 		error = authenticate_root_with_chunklist(path, &auth_root);
1099*bbb1b6f9SApple OSS Distributions 		if (error) {
1100*bbb1b6f9SApple OSS Distributions 			panic("root image authentication failed (err = %d)", error);
1101*bbb1b6f9SApple OSS Distributions 		}
1102*bbb1b6f9SApple OSS Distributions 		AUTHDBG("successfully authenticated %s", path);
1103*bbb1b6f9SApple OSS Distributions 	}
1104*bbb1b6f9SApple OSS Distributions #endif
1105*bbb1b6f9SApple OSS Distributions 
1106*bbb1b6f9SApple OSS Distributions 	if (ramdisk_root) {
1107*bbb1b6f9SApple OSS Distributions 		error = imageboot_mount_ramdisk(path);
1108*bbb1b6f9SApple OSS Distributions 	} else {
1109*bbb1b6f9SApple OSS Distributions 		error = imageboot_mount_image(root_path, height, type);
1110*bbb1b6f9SApple OSS Distributions 	}
1111*bbb1b6f9SApple OSS Distributions 
1112*bbb1b6f9SApple OSS Distributions 	if (path != root_path) {
1113*bbb1b6f9SApple OSS Distributions 		kfree_data(path, pathsz);
1114*bbb1b6f9SApple OSS Distributions 	}
1115*bbb1b6f9SApple OSS Distributions 
1116*bbb1b6f9SApple OSS Distributions 	if (error) {
1117*bbb1b6f9SApple OSS Distributions 		if (error == EFBIG) {
1118*bbb1b6f9SApple OSS Distributions 			panic("root imagefile is too large (err=%d, auth=%d, ramdisk=%d)",
1119*bbb1b6f9SApple OSS Distributions 			    error, auth_root, ramdisk_root);
1120*bbb1b6f9SApple OSS Distributions 		} else {
1121*bbb1b6f9SApple OSS Distributions 			panic("Failed to mount root image (err=%d, auth=%d, ramdisk=%d)",
1122*bbb1b6f9SApple OSS Distributions 			    error, auth_root, ramdisk_root);
1123*bbb1b6f9SApple OSS Distributions 		}
1124*bbb1b6f9SApple OSS Distributions 	}
1125*bbb1b6f9SApple OSS Distributions 
1126*bbb1b6f9SApple OSS Distributions #if CONFIG_IMAGEBOOT_CHUNKLIST
1127*bbb1b6f9SApple OSS Distributions 	if (auth_root) {
1128*bbb1b6f9SApple OSS Distributions 		/* check that the image version matches the running kernel */
1129*bbb1b6f9SApple OSS Distributions 		AUTHDBG("checking root image version");
1130*bbb1b6f9SApple OSS Distributions 		error = authenticate_root_version_check();
1131*bbb1b6f9SApple OSS Distributions 		if (error) {
1132*bbb1b6f9SApple OSS Distributions 			panic("root image version check failed");
1133*bbb1b6f9SApple OSS Distributions 		} else {
1134*bbb1b6f9SApple OSS Distributions 			AUTHDBG("root image version matches kernel");
1135*bbb1b6f9SApple OSS Distributions 		}
1136*bbb1b6f9SApple OSS Distributions 	}
1137*bbb1b6f9SApple OSS Distributions #endif
1138*bbb1b6f9SApple OSS Distributions 
1139*bbb1b6f9SApple OSS Distributions 	done = TRUE;
1140*bbb1b6f9SApple OSS Distributions 
1141*bbb1b6f9SApple OSS Distributions out:
1142*bbb1b6f9SApple OSS Distributions 	zfree(ZV_NAMEI, root_path);
1143*bbb1b6f9SApple OSS Distributions 	return done;
1144*bbb1b6f9SApple OSS Distributions }
1145*bbb1b6f9SApple OSS Distributions 
1146*bbb1b6f9SApple OSS Distributions __private_extern__ void
imageboot_setup(imageboot_type_t type)1147*bbb1b6f9SApple OSS Distributions imageboot_setup(imageboot_type_t type)
1148*bbb1b6f9SApple OSS Distributions {
1149*bbb1b6f9SApple OSS Distributions 	int         error = 0;
1150*bbb1b6f9SApple OSS Distributions 	char *root_path = NULL;
1151*bbb1b6f9SApple OSS Distributions 
1152*bbb1b6f9SApple OSS Distributions 	DBG_TRACE("%s: entry\n", __FUNCTION__);
1153*bbb1b6f9SApple OSS Distributions 
1154*bbb1b6f9SApple OSS Distributions 	if (rootvnode == NULL) {
1155*bbb1b6f9SApple OSS Distributions 		panic("imageboot_setup: rootvnode is NULL.");
1156*bbb1b6f9SApple OSS Distributions 	}
1157*bbb1b6f9SApple OSS Distributions 
1158*bbb1b6f9SApple OSS Distributions 	/*
1159*bbb1b6f9SApple OSS Distributions 	 * New boot-arg scheme:
1160*bbb1b6f9SApple OSS Distributions 	 *      root-dmg : the dmg that will be the root filesystem, authenticated by default.
1161*bbb1b6f9SApple OSS Distributions 	 *      auth-root-dmg : same as root-dmg.
1162*bbb1b6f9SApple OSS Distributions 	 *      container-dmg : an optional dmg that contains the root-dmg.
1163*bbb1b6f9SApple OSS Distributions 	 *  locker : the locker that will be the root filesystem -- mutually
1164*bbb1b6f9SApple OSS Distributions 	 *           exclusive with any other boot-arg.
1165*bbb1b6f9SApple OSS Distributions 	 */
1166*bbb1b6f9SApple OSS Distributions 	if (imageboot_setup_new(type)) {
1167*bbb1b6f9SApple OSS Distributions 		return;
1168*bbb1b6f9SApple OSS Distributions 	}
1169*bbb1b6f9SApple OSS Distributions 
1170*bbb1b6f9SApple OSS Distributions 	root_path = zalloc(ZV_NAMEI);
1171*bbb1b6f9SApple OSS Distributions 	assert(root_path != NULL);
1172*bbb1b6f9SApple OSS Distributions 
1173*bbb1b6f9SApple OSS Distributions 	/*
1174*bbb1b6f9SApple OSS Distributions 	 * Look for outermost disk image to root from.  If we're doing a nested boot,
1175*bbb1b6f9SApple OSS Distributions 	 * there's some sense in which the outer image never needs to be the root filesystem,
1176*bbb1b6f9SApple OSS Distributions 	 * but it does need very similar treatment: it must not be unmounted, needs a fake
1177*bbb1b6f9SApple OSS Distributions 	 * device vnode created for it, and should not show up in getfsstat() until exposed
1178*bbb1b6f9SApple OSS Distributions 	 * with MNT_IMGSRC. We just make it the temporary root.
1179*bbb1b6f9SApple OSS Distributions 	 */
1180*bbb1b6f9SApple OSS Distributions #if CONFIG_IMAGEBOOT_IMG4
1181*bbb1b6f9SApple OSS Distributions 	if (PE_parse_boot_argn("arp0", root_path, MAXPATHLEN)) {
1182*bbb1b6f9SApple OSS Distributions 		size_t pathsz;
1183*bbb1b6f9SApple OSS Distributions 		char *path = url_to_path(root_path, &pathsz);
1184*bbb1b6f9SApple OSS Distributions 
1185*bbb1b6f9SApple OSS Distributions 		assert(path);
1186*bbb1b6f9SApple OSS Distributions 
1187*bbb1b6f9SApple OSS Distributions 		if (authenticate_root_with_img4(path)) {
1188*bbb1b6f9SApple OSS Distributions 			panic("Root image %s does not match the manifest", root_path);
1189*bbb1b6f9SApple OSS Distributions 		}
1190*bbb1b6f9SApple OSS Distributions 		if (path != root_path) {
1191*bbb1b6f9SApple OSS Distributions 			kfree_data(path, pathsz);
1192*bbb1b6f9SApple OSS Distributions 		}
1193*bbb1b6f9SApple OSS Distributions 	} else
1194*bbb1b6f9SApple OSS Distributions #endif /* CONFIG_IMAGEBOOT_IMG4 */
1195*bbb1b6f9SApple OSS Distributions 	if ((PE_parse_boot_argn("rp", root_path, MAXPATHLEN) == FALSE) &&
1196*bbb1b6f9SApple OSS Distributions 	    (PE_parse_boot_argn("rp0", root_path, MAXPATHLEN) == FALSE)) {
1197*bbb1b6f9SApple OSS Distributions 		panic("%s: no valid path to image.", __FUNCTION__);
1198*bbb1b6f9SApple OSS Distributions 	}
1199*bbb1b6f9SApple OSS Distributions 
1200*bbb1b6f9SApple OSS Distributions 	DBG_TRACE("%s: root image url is %s\n", __FUNCTION__, root_path);
1201*bbb1b6f9SApple OSS Distributions 
1202*bbb1b6f9SApple OSS Distributions 	error = imageboot_mount_image(root_path, 0, type);
1203*bbb1b6f9SApple OSS Distributions 	if (error) {
1204*bbb1b6f9SApple OSS Distributions 		panic("Failed on first stage of imageboot.");
1205*bbb1b6f9SApple OSS Distributions 	}
1206*bbb1b6f9SApple OSS Distributions 
1207*bbb1b6f9SApple OSS Distributions 	/*
1208*bbb1b6f9SApple OSS Distributions 	 * See if we are rooting from a nested image
1209*bbb1b6f9SApple OSS Distributions 	 */
1210*bbb1b6f9SApple OSS Distributions 	if (PE_parse_boot_argn("rp1", root_path, MAXPATHLEN) == FALSE) {
1211*bbb1b6f9SApple OSS Distributions 		goto done;
1212*bbb1b6f9SApple OSS Distributions 	}
1213*bbb1b6f9SApple OSS Distributions 
1214*bbb1b6f9SApple OSS Distributions 	printf("%s: second level root image url is %s\n", __FUNCTION__, root_path);
1215*bbb1b6f9SApple OSS Distributions 
1216*bbb1b6f9SApple OSS Distributions 	/*
1217*bbb1b6f9SApple OSS Distributions 	 * If we fail to set up second image, it's not a given that we
1218*bbb1b6f9SApple OSS Distributions 	 * can safely root off the first.
1219*bbb1b6f9SApple OSS Distributions 	 */
1220*bbb1b6f9SApple OSS Distributions 	error = imageboot_mount_image(root_path, 1, type);
1221*bbb1b6f9SApple OSS Distributions 	if (error) {
1222*bbb1b6f9SApple OSS Distributions 		panic("Failed on second stage of imageboot.");
1223*bbb1b6f9SApple OSS Distributions 	}
1224*bbb1b6f9SApple OSS Distributions 
1225*bbb1b6f9SApple OSS Distributions done:
1226*bbb1b6f9SApple OSS Distributions 	zfree(ZV_NAMEI, root_path);
1227*bbb1b6f9SApple OSS Distributions 
1228*bbb1b6f9SApple OSS Distributions 	DBG_TRACE("%s: exit\n", __FUNCTION__);
1229*bbb1b6f9SApple OSS Distributions 
1230*bbb1b6f9SApple OSS Distributions 	return;
1231*bbb1b6f9SApple OSS Distributions }
1232