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