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