2 * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #include <sys/param.h>
30 #include <sys/kernel.h>
31 #include <sys/proc_internal.h>
32 #include <sys/systm.h>
33 #include <sys/systm.h>
34 #include <sys/mount_internal.h>
35 #include <sys/filedesc.h>
36 #include <sys/vnode_internal.h>
37 #include <sys/imageboot.h>
38 #include <kern/assert.h>
40 #include <sys/namei.h>
41 #include <sys/fcntl.h>
42 #include <sys/vnode.h>
43 #include <sys/sysproto.h>
45 #include <miscfs/devfs/devfsdefs.h>
46 #include <libkern/crypto/sha2.h>
47 #include <libkern/crypto/rsa.h>
48 #include <libkern/OSKextLibPrivate.h>
50 #include <kern/kalloc.h>
52 #include <pexpert/pexpert.h>
53 #include <kern/chunklist.h>
55 extern struct filedesc filedesc0
;
57 extern int (*mountroot
)(void);
58 extern char rootdevice
[DEVMAXNAMESIZE
];
60 #define DEBUG_IMAGEBOOT 0
63 #define DBG_TRACE(...) printf(__VA_ARGS__)
65 #define DBG_TRACE(...) do {} while(0)
68 extern int di_root_image(const char *path
, char *devname
, size_t devsz
, dev_t
*dev_p
);
69 extern int di_root_ramfile_buf(void *buf
, size_t bufsz
, char *devname
, size_t devsz
, dev_t
*dev_p
);
71 static boolean_t
imageboot_setup_new(void);
73 #define kIBFilePrefix "file://"
75 __private_extern__
int
76 imageboot_format_is_valid(const char *root_path
)
78 return (strncmp(root_path
, kIBFilePrefix
,
79 strlen(kIBFilePrefix
)) == 0);
83 vnode_get_and_drop_always(vnode_t vp
)
90 __private_extern__
int
91 imageboot_needed(void)
94 char *root_path
= NULL
;
96 DBG_TRACE("%s: checking for presence of root path\n", __FUNCTION__
);
98 MALLOC_ZONE(root_path
, caddr_t
, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
99 if (root_path
== NULL
)
100 panic("%s: M_NAMEI zone exhausted", __FUNCTION__
);
102 /* Check for first layer */
103 if (!(PE_parse_boot_argn("rp0", root_path
, MAXPATHLEN
) ||
104 PE_parse_boot_argn("rp", root_path
, MAXPATHLEN
) ||
105 PE_parse_boot_argn(IMAGEBOOT_ROOT_ARG
, root_path
, MAXPATHLEN
) ||
106 PE_parse_boot_argn(IMAGEBOOT_AUTHROOT_ARG
, root_path
, MAXPATHLEN
))) {
110 /* Sanity-check first layer */
111 if (imageboot_format_is_valid(root_path
)) {
112 DBG_TRACE("%s: Found %s\n", __FUNCTION__
, root_path
);
119 /* Check for second layer */
120 if (!(PE_parse_boot_argn("rp1", root_path
, MAXPATHLEN
) ||
121 PE_parse_boot_argn(IMAGEBOOT_CONTAINER_ARG
, root_path
, MAXPATHLEN
))) {
125 /* Sanity-check second layer */
126 if (imageboot_format_is_valid(root_path
)) {
127 DBG_TRACE("%s: Found %s\n", __FUNCTION__
, root_path
);
129 panic("%s: Invalid URL scheme for %s\n",
130 __FUNCTION__
, root_path
);
134 FREE_ZONE(root_path
, MAXPATHLEN
, M_NAMEI
);
141 * Swaps in new root filesystem based on image path.
142 * Current root filesystem is removed from mount list and
143 * tagged MNTK_BACKS_ROOT, MNT_ROOTFS is cleared on it, and
144 * "rootvnode" is reset. Root vnode of currentroot filesystem
145 * is returned with usecount (no iocount).
147 __private_extern__
int
148 imageboot_mount_image(const char *root_path
, int height
)
152 vnode_t old_rootvnode
= NULL
;
156 error
= di_root_image(root_path
, rootdevice
, DEVMAXNAMESIZE
, &dev
);
158 panic("%s: di_root_image failed: %d\n", __FUNCTION__
, error
);
163 printf("%s: root device 0x%x\n", __FUNCTION__
, rootdev
);
164 error
= vfs_mountroot();
166 panic("vfs_mountroot() failed.\n");
170 * Get the vnode for '/'.
171 * Set fdp->fd_fd.fd_cdir to reference it.
173 if (VFS_ROOT(TAILQ_LAST(&mountlist
,mntlist
), &newdp
, vfs_context_kernel()))
174 panic("%s: cannot find root vnode", __FUNCTION__
);
176 if (rootvnode
!= NULL
) {
177 /* remember the old rootvnode, but remove it from mountlist */
180 old_rootvnode
= rootvnode
;
181 old_rootfs
= rootvnode
->v_mount
;
183 mount_list_remove(old_rootfs
);
185 mount_lock(old_rootfs
);
186 #ifdef CONFIG_IMGSRC_ACCESS
187 old_rootfs
->mnt_kern_flag
|= MNTK_BACKS_ROOT
;
188 #endif /* CONFIG_IMGSRC_ACCESS */
189 old_rootfs
->mnt_flag
&= ~MNT_ROOTFS
;
190 mount_unlock(old_rootfs
);
193 /* switch to the new rootvnode */
196 new_rootfs
= rootvnode
->v_mount
;
197 mount_lock(new_rootfs
);
198 new_rootfs
->mnt_flag
|= MNT_ROOTFS
;
199 mount_unlock(new_rootfs
);
203 filedesc0
.fd_cdir
= newdp
;
204 DBG_TRACE("%s: root switched\n", __FUNCTION__
);
206 if (old_rootvnode
!= NULL
) {
207 #ifdef CONFIG_IMGSRC_ACCESS
208 if (height
>= 0 && PE_imgsrc_mount_supported()) {
209 imgsrc_rootvnodes
[height
] = old_rootvnode
;
211 vnode_get_and_drop_always(old_rootvnode
);
214 height
= 0; /* keep the compiler from complaining */
215 vnode_get_and_drop_always(old_rootvnode
);
216 #endif /* CONFIG_IMGSRC_ACCESS */
223 * Authenticated root-dmg support
226 #define AUTHDBG(fmt, args...) do { printf("%s: " fmt "\n", __func__, ##args); } while (0)
227 #define AUTHPRNT(fmt, args...) do { printf("%s: " fmt "\n", __func__, ##args); } while (0)
229 #define kfree_safe(x) do { if ((x)) { kfree_addr((x)); (x) = NULL; } } while (0)
237 key_byteswap(void *_dst
, const void *_src
, size_t len
)
239 uint32_t *dst
__attribute__((align_value(1))) = _dst
;
240 const uint32_t *src
__attribute__((align_value(1))) = _src
;
242 assert(len
% sizeof(uint32_t) == 0);
244 len
= len
/ sizeof(uint32_t);
245 for (size_t i
= 0; i
< len
; i
++) {
246 dst
[len
-i
-1] = OSSwapInt32(src
[i
]);
251 read_file(const char *path
, void **bufp
, size_t *bufszp
)
254 struct nameidata ndp
= {};
255 struct vnode
*vp
= NULL
;
259 bool doclose
= false;
261 vfs_context_t ctx
= vfs_context_kernel();
262 proc_t p
= vfs_context_proc(ctx
);
263 kauth_cred_t kerncred
= vfs_context_ucred(ctx
);
265 NDINIT(&ndp
, LOOKUP
, OP_OPEN
, LOCKLEAF
, UIO_SYSSPACE
, CAST_USER_ADDR_T(path
), ctx
);
266 if ((err
= namei(&ndp
)) != 0) {
267 AUTHPRNT("namei failed (%s)", path
);
273 if ((err
= vnode_size(vp
, &fsize
, ctx
)) != 0) {
274 AUTHPRNT("failed to get vnode size");
278 panic("negative file size");
281 if ((err
= VNOP_OPEN(vp
, FREAD
, ctx
)) != 0) {
282 AUTHPRNT("failed to open vnode");
287 /* if bufsz is non-zero, cap the read at bufsz bytes */
288 if (*bufszp
&& *bufszp
< (size_t)fsize
) {
298 if ((err
= vn_rdwr(UIO_READ
, vp
, (caddr_t
)buf
, fsize
, 0, UIO_SYSSPACE
, IO_NODELOCKED
, kerncred
, &resid
, p
)) != 0) {
299 AUTHPRNT("vn_rdwr() failed");
304 /* didnt get everything we wanted */
305 AUTHPRNT("vn_rdwr resid = %d", resid
);
312 VNOP_CLOSE(vp
, FREAD
, ctx
);
330 validate_signature(const uint8_t *key_msb
, size_t keylen
, uint8_t *sig_msb
, size_t siglen
, uint8_t *digest
)
333 bool sig_valid
= false;
336 const uint8_t exponent
[] = { 0x01, 0x00, 0x01 };
337 uint8_t *modulus
= kalloc(keylen
);
338 rsa_pub_ctx
*rsa_ctx
= kalloc(sizeof(rsa_pub_ctx
));
339 sig
= kalloc(siglen
);
341 if (modulus
== NULL
|| rsa_ctx
== NULL
|| sig
== NULL
) {
346 bzero(rsa_ctx
, sizeof(rsa_pub_ctx
));
347 key_byteswap(modulus
, key_msb
, keylen
);
348 key_byteswap(sig
, sig_msb
, siglen
);
350 err
= rsa_make_pub(rsa_ctx
,
351 sizeof(exponent
), exponent
,
352 CHUNKLIST_PUBKEY_LEN
, modulus
);
354 AUTHPRNT("rsa_make_pub() failed");
358 err
= rsa_verify_pkcs1v15(rsa_ctx
, CC_DIGEST_OID_SHA256
,
359 SHA256_DIGEST_LENGTH
, digest
,
364 AUTHPRNT("rsa_verify() failed");
376 } else if (sig_valid
== true) {
377 return 0; /* success */
384 validate_chunklist(void *buf
, size_t len
)
389 size_t chunks_end
= 0;
390 bool valid_sig
= false;
391 struct chunklist_hdr
*hdr
= buf
;
393 if (len
< sizeof(struct chunklist_hdr
)) {
394 AUTHPRNT("no space for header");
398 /* recognized file format? */
399 if (hdr
->cl_magic
!= CHUNKLIST_MAGIC
||
400 hdr
->cl_file_ver
!= CHUNKLIST_FILE_VERSION_10
||
401 hdr
->cl_chunk_method
!= CHUNKLIST_SIGNATURE_METHOD_10
||
402 hdr
->cl_sig_method
!= CHUNKLIST_SIGNATURE_METHOD_10
) {
403 AUTHPRNT("unrecognized chunklist format");
407 /* does the chunk list fall within the bounds of the buffer? */
408 if (os_mul_and_add_overflow(hdr
->cl_chunk_count
, sizeof(struct chunklist_chunk
), hdr
->cl_chunk_offset
, &chunks_end
) ||
409 hdr
->cl_chunk_offset
< sizeof(struct chunklist_hdr
) || chunks_end
> len
) {
410 AUTHPRNT("invalid chunk_count (%llu) or chunk_offset (%llu)",
411 hdr
->cl_chunk_count
, hdr
->cl_chunk_offset
);
415 /* does the signature fall within the bounds of the buffer? */
416 if (os_add_overflow(hdr
->cl_sig_offset
, sizeof(struct chunklist_sig
), &sig_end
) ||
417 hdr
->cl_sig_offset
< sizeof(struct chunklist_hdr
) ||
418 hdr
->cl_sig_offset
< chunks_end
||
419 hdr
->cl_sig_offset
> len
) {
420 AUTHPRNT("invalid signature offset (%llu)", hdr
->cl_sig_offset
);
424 if (sig_end
> len
|| os_sub_overflow(len
, hdr
->cl_sig_offset
, &sigsz
) || sigsz
!= CHUNKLIST_SIG_LEN
) {
425 /* missing or incorrect signature size */
429 AUTHDBG("hashing chunklist");
431 /* hash the chunklist (excluding the signature) */
432 uint8_t sha_digest
[SHA256_DIGEST_LENGTH
];
434 SHA256_Init(&sha_ctx
);
435 SHA256_Update(&sha_ctx
, buf
, hdr
->cl_sig_offset
);
436 SHA256_Final(sha_digest
, &sha_ctx
);
438 AUTHDBG("validating chunklist signature against pub keys");
439 for (size_t i
= 0; i
< CHUNKLIST_NPUBKEYS
; i
++) {
440 const struct chunklist_pubkey
*key
= &chunklist_pubkeys
[i
];
441 err
= validate_signature(key
->key
, CHUNKLIST_PUBKEY_LEN
,
442 buf
+ hdr
->cl_sig_offset
, sigsz
, sha_digest
);
444 AUTHDBG("validated chunklist signature with key %lu (prod=%d)", i
, key
->isprod
);
445 valid_sig
= key
->isprod
;
446 #if IMAGEBOOT_ALLOW_DEVKEYS
448 /* allow dev keys in dev builds only */
449 AUTHDBG("*** allowing DEV key: this will fail in customer builds ***");
454 } else if (err
== INVALID_SIG
) {
455 /* try the next key */
457 goto out
; /* something bad happened */
461 /* At this point we tried all the keys: nothing went wrong but none of them
462 * signed our chunklist. */
463 AUTHPRNT("signature did not verify against any known public key");
468 } else if (valid_sig
== true) {
469 return 0; /* signed, and everything checked out */
476 validate_root_image(const char *root_path
, void *chunklist
)
479 struct chunklist_hdr
*hdr
= chunklist
;
480 struct chunklist_chunk
*chk
= NULL
;
482 struct nameidata ndp
= {};
483 struct vnode
*vp
= NULL
;
486 bool doclose
= false;
490 vfs_context_t ctx
= vfs_context_kernel();
491 kauth_cred_t kerncred
= vfs_context_ucred(ctx
);
492 proc_t p
= vfs_context_proc(ctx
);
494 AUTHDBG("validating root dmg %s", root_path
);
499 NDINIT(&ndp
, LOOKUP
, OP_OPEN
, LOCKLEAF
, UIO_SYSSPACE
, CAST_USER_ADDR_T(root_path
), ctx
);
500 if ((err
= namei(&ndp
)) != 0) {
501 AUTHPRNT("namei failed (%s)", root_path
);
507 if (vp
->v_type
!= VREG
) {
512 if ((err
= vnode_size(vp
, &fsize
, ctx
)) != 0) {
513 AUTHPRNT("failed to get vnode size");
517 if ((err
= VNOP_OPEN(vp
, FREAD
, ctx
)) != 0) {
518 AUTHPRNT("failed to open vnode");
524 * Iterate the chunk list and check each chunk
526 chk
= chunklist
+ hdr
->cl_chunk_offset
;
527 for (ch
= 0; ch
< hdr
->cl_chunk_count
; ch
++) {
531 /* allocate buffer based on first chunk size */
532 buf
= kalloc(chk
->chunk_size
);
537 bufsz
= chk
->chunk_size
;
540 if (chk
->chunk_size
> bufsz
) {
541 AUTHPRNT("chunk size too big");
546 err
= vn_rdwr(UIO_READ
, vp
, (caddr_t
)buf
, chk
->chunk_size
, offset
, UIO_SYSSPACE
, IO_NODELOCKED
, kerncred
, &resid
, p
);
548 AUTHPRNT("vn_rdrw fail (err = %d, resid = %d)", err
, resid
);
553 AUTHPRNT("chunk covered non-existant part of image");
557 /* calculate the SHA256 of this chunk */
558 uint8_t sha_digest
[SHA256_DIGEST_LENGTH
];
560 SHA256_Init(&sha_ctx
);
561 SHA256_Update(&sha_ctx
, buf
, chk
->chunk_size
);
562 SHA256_Final(sha_digest
, &sha_ctx
);
564 /* Check the calculated SHA matches the chunk list */
565 if (bcmp(sha_digest
, chk
->chunk_sha256
, SHA256_DIGEST_LENGTH
) != 0) {
566 AUTHPRNT("SHA mismatch on chunk %lu (offset %lld, size %u)", ch
, offset
, chk
->chunk_size
);
571 if (os_add_overflow(offset
, chk
->chunk_size
, &offset
)) {
578 if (offset
!= fsize
) {
579 AUTHPRNT("chunklist did not cover entire file (offset = %lld, fsize = %lld)", offset
, fsize
);
587 VNOP_CLOSE(vp
, FREAD
, ctx
);
598 construct_chunklist_path(const char *root_path
, char **bufp
)
604 path
= kalloc(MAXPATHLEN
);
606 AUTHPRNT("failed to allocate space for chunklist path");
611 len
= strnlen(root_path
, MAXPATHLEN
);
612 if (len
< MAXPATHLEN
&& len
> strlen(".dmg")) {
613 /* correctly terminated string with space for extension */
615 AUTHPRNT("malformed root path");
620 len
= strlcpy(path
, root_path
, MAXPATHLEN
);
621 if (len
>= MAXPATHLEN
) {
622 AUTHPRNT("root path is too long");
627 path
[len
- strlen(".dmg")] = '\0';
628 len
= strlcat(path
, ".chunklist", MAXPATHLEN
);
629 if (len
>= MAXPATHLEN
) {
630 AUTHPRNT("chunklist path is too long");
645 authenticate_root(const char *root_path
)
647 char *chunklist_path
= NULL
;
648 void *chunklist_buf
= NULL
;
649 size_t chunklist_len
= 32*1024*1024UL;
652 err
= construct_chunklist_path(root_path
, &chunklist_path
);
654 AUTHPRNT("failed creating chunklist path");
658 AUTHDBG("validating root against chunklist %s", chunklist_path
);
661 * Read and authenticate the chunklist, then validate the root image against
665 AUTHDBG("reading chunklist");
666 err
= read_file(chunklist_path
, &chunklist_buf
, &chunklist_len
);
668 AUTHPRNT("failed to read chunklist");
672 AUTHDBG("validating chunklist");
673 err
= validate_chunklist(chunklist_buf
, chunklist_len
);
675 AUTHDBG("missing or incorrect signature on chunklist");
678 AUTHPRNT("failed to validate chunklist");
681 AUTHDBG("successfully validated chunklist");
684 AUTHDBG("validating root image against chunklist");
685 err
= validate_root_image(root_path
, chunklist_buf
);
687 AUTHPRNT("failed to validate root image against chunklist (%d)", err
);
691 /* everything checked out - go ahead and mount this */
692 AUTHDBG("root image authenticated");
695 kfree_safe(chunklist_buf
);
696 kfree_safe(chunklist_path
);
700 static const uuid_t
*
701 getuuidfromheader_safe(const void *buf
, size_t bufsz
, size_t *uuidsz
)
703 const struct uuid_command
*cmd
= NULL
;
704 const kernel_mach_header_t
*mh
= buf
;
706 /* space for the header and at least one load command? */
707 if (bufsz
< sizeof(kernel_mach_header_t
) + sizeof(struct uuid_command
)) {
708 AUTHPRNT("libkern image too small");
712 /* validate the mach header */
713 if (mh
->magic
!= MH_MAGIC_64
|| (mh
->sizeofcmds
> bufsz
- sizeof(kernel_mach_header_t
))) {
714 AUTHPRNT("invalid MachO header");
718 /* iterate the load commands */
719 size_t offset
= sizeof(kernel_mach_header_t
);
720 for (size_t i
= 0; i
< mh
->ncmds
; i
++) {
723 if (cmd
->cmd
== LC_UUID
) {
724 *uuidsz
= sizeof(cmd
->uuid
);
728 if (os_add_overflow(cmd
->cmdsize
, offset
, &offset
) ||
729 offset
> bufsz
- sizeof(struct uuid_command
)) {
737 static const char *libkern_path
= "/System/Library/Extensions/System.kext/PlugIns/Libkern.kext/Libkern";
738 static const char *libkern_bundle
= "com.apple.kpi.libkern";
741 * Check that the UUID of the libkern currently loaded matches the one on disk.
744 auth_version_check(void)
748 size_t bufsz
= 4*1024*1024UL;
750 /* get the UUID of the libkern in /S/L/E */
752 err
= read_file(libkern_path
, &buf
, &bufsz
);
757 unsigned long uuidsz
= 0;
758 const uuid_t
*img_uuid
= getuuidfromheader_safe(buf
, bufsz
, &uuidsz
);
759 if (img_uuid
== NULL
|| uuidsz
!= sizeof(uuid_t
)) {
760 AUTHPRNT("invalid UUID (sz = %lu)", uuidsz
);
765 /* Get the UUID of the loaded libkern */
767 err
= OSKextGetUUIDForName(libkern_bundle
, live_uuid
);
769 AUTHPRNT("could not find loaded libkern");
773 /* ... and compare them */
774 if (bcmp(live_uuid
, img_uuid
, uuidsz
) != 0) {
775 AUTHPRNT("UUID of running libkern does not match %s", libkern_path
);
777 uuid_string_t img_uuid_str
, live_uuid_str
;
778 uuid_unparse(*img_uuid
, img_uuid_str
);
779 uuid_unparse(live_uuid
, live_uuid_str
);
780 AUTHPRNT("loaded libkern UUID = %s", live_uuid_str
);
781 AUTHPRNT("on-disk libkern UUID = %s", img_uuid_str
);
796 auth_imgboot_test(proc_t __unused ap
, struct auth_imgboot_test_args
*uap
, int32_t *retval
)
800 char path
[MAXPATHLEN
];
804 err
= copyinstr(uap
->path
, path
, MAXPATHLEN
, &len
);
808 if (len
>= MAXPATHLEN
) {
812 AUTHDBG("authenticating root image at %s", path
);
813 err
= authenticate_root(path
);
815 AUTHPRNT("root authentication FAIL (%d)", err
);
818 AUTHDBG("successfully authenticated %s", path
);
821 AUTHDBG("checking root image version");
822 err
= auth_version_check();
824 AUTHPRNT("root image version check FAIL (%d)", err
);
827 AUTHPRNT("root version check success (%d)", err
);
831 return EINVAL
; /* negative return values have special meaning */
838 * Attach the image at 'path' as a ramdisk and mount it as our new rootfs.
839 * All existing mounts are first umounted.
842 imageboot_mount_ramdisk(const char *path
)
851 /* Read our target image from disk */
852 err
= read_file(path
, &buf
, &bufsz
);
854 printf("%s: failed: read_file() = %d\n", __func__
, err
);
857 DBG_TRACE("%s: read '%s' sz = %lu\n", __func__
, path
, bufsz
);
859 #if CONFIG_IMGSRC_ACCESS
860 /* Re-add all root mounts to the mount list in the correct order... */
861 mount_list_remove(rootvnode
->v_mount
);
862 for (int i
= 0; i
< MAX_IMAGEBOOT_NESTING
; i
++) {
863 struct vnode
*vn
= imgsrc_rootvnodes
[i
];
866 imgsrc_rootvnodes
[i
] = NULLVP
;
868 mount_t mnt
= vn
->v_mount
;
870 mnt
->mnt_flag
|= MNT_ROOTFS
;
878 mount_list_add(rootvnode
->v_mount
);
881 /* ... and unmount everything */
882 vnode_get_and_drop_always(rootvnode
);
883 filedesc0
.fd_cdir
= NULL
;
887 /* Attach the ramfs image ... */
888 err
= di_root_ramfile_buf(buf
, bufsz
, rootdevice
, DEVMAXNAMESIZE
, &dev
);
890 printf("%s: failed: di_root_ramfile_buf() = %d\n", __func__
, err
);
894 /* ... and mount it */
897 err
= vfs_mountroot();
899 printf("%s: failed: vfs_mountroot() = %d\n", __func__
, err
);
903 /* Switch to new root vnode */
904 if (VFS_ROOT(TAILQ_LAST(&mountlist
,mntlist
), &newdp
, vfs_context_kernel())) {
905 panic("%s: cannot find root vnode", __func__
);
908 rootvnode
->v_flag
|= VROOT
;
909 new_rootfs
= rootvnode
->v_mount
;
910 mount_lock(new_rootfs
);
911 new_rootfs
->mnt_flag
|= MNT_ROOTFS
;
912 mount_unlock(new_rootfs
);
916 filedesc0
.fd_cdir
= newdp
;
918 DBG_TRACE("%s: root switched\n", __func__
);
928 imageboot_setup_new()
931 char *root_path
= NULL
;
933 boolean_t done
= FALSE
;
934 boolean_t auth_root
= FALSE
;
935 boolean_t ramdisk_root
= FALSE
;
937 MALLOC_ZONE(root_path
, caddr_t
, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
938 assert(root_path
!= NULL
);
940 unsigned imgboot_arg
;
941 if (PE_parse_boot_argn("-rootdmg-ramdisk", &imgboot_arg
, sizeof(imgboot_arg
))) {
945 if (PE_parse_boot_argn(IMAGEBOOT_CONTAINER_ARG
, root_path
, MAXPATHLEN
) == TRUE
) {
946 printf("%s: container image url is %s\n", __FUNCTION__
, root_path
);
947 error
= imageboot_mount_image(root_path
, height
);
949 panic("Failed to mount container image.");
955 if (PE_parse_boot_argn(IMAGEBOOT_AUTHROOT_ARG
, root_path
, MAXPATHLEN
) == TRUE
) {
957 } else if (PE_parse_boot_argn(IMAGEBOOT_ROOT_ARG
, root_path
, MAXPATHLEN
) == FALSE
) {
959 panic("%s specified without %s?\n", IMAGEBOOT_CONTAINER_ARG
, IMAGEBOOT_ROOT_ARG
);
964 printf("%s: root image url is %s\n", __func__
, root_path
);
967 if (auth_root
&& (csr_check(CSR_ALLOW_ANY_RECOVERY_OS
) == 0)) {
968 AUTHPRNT("CSR_ALLOW_ANY_RECOVERY_OS set, skipping root image authentication");
973 /* Make a copy of the path to URL-decode */
974 char *path_alloc
= kalloc(MAXPATHLEN
);
975 if (path_alloc
== NULL
) {
976 panic("imageboot path allocation failed\n");
978 char *path
= path_alloc
;
980 size_t len
= strlen(kIBFilePrefix
);
981 strlcpy(path
, root_path
, MAXPATHLEN
);
982 if (strncmp(kIBFilePrefix
, path
, len
) == 0) {
983 /* its a URL - remove the file:// prefix and percent-decode */
989 AUTHDBG("authenticating root image at %s", path
);
990 error
= authenticate_root(path
);
992 panic("root image authentication failed (err = %d)\n", error
);
994 AUTHDBG("successfully authenticated %s", path
);
998 error
= imageboot_mount_ramdisk(path
);
1000 error
= imageboot_mount_image(root_path
, height
);
1003 kfree_safe(path_alloc
);
1006 panic("Failed to mount root image (err=%d, auth=%d, ramdisk=%d)\n",
1007 error
, auth_root
, ramdisk_root
);
1011 /* check that the image version matches the running kernel */
1012 AUTHDBG("checking root image version");
1013 error
= auth_version_check();
1015 panic("root image version check failed");
1017 AUTHDBG("root image version matches kernel");
1024 FREE_ZONE(root_path
, MAXPATHLEN
, M_NAMEI
);
1028 __private_extern__
void
1032 char *root_path
= NULL
;
1034 DBG_TRACE("%s: entry\n", __FUNCTION__
);
1036 if (rootvnode
== NULL
) {
1037 panic("imageboot_setup: rootvnode is NULL.");
1041 * New boot-arg scheme:
1042 * root-dmg : the dmg that will be the root filesystem.
1043 * auth-root-dmg : same as root-dmg but with image authentication.
1044 * container-dmg : an optional dmg that contains the root-dmg.
1046 if (imageboot_setup_new()) {
1050 MALLOC_ZONE(root_path
, caddr_t
, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
1051 assert(root_path
!= NULL
);
1054 * Look for outermost disk image to root from. If we're doing a nested boot,
1055 * there's some sense in which the outer image never needs to be the root filesystem,
1056 * but it does need very similar treatment: it must not be unmounted, needs a fake
1057 * device vnode created for it, and should not show up in getfsstat() until exposed
1058 * with MNT_IMGSRC. We just make it the temporary root.
1060 if((PE_parse_boot_argn("rp", root_path
, MAXPATHLEN
) == FALSE
) &&
1061 (PE_parse_boot_argn("rp0", root_path
, MAXPATHLEN
) == FALSE
)) {
1062 panic("%s: no valid path to image.\n", __FUNCTION__
);
1065 printf("%s: root image url is %s\n", __FUNCTION__
, root_path
);
1067 error
= imageboot_mount_image(root_path
, 0);
1069 panic("Failed on first stage of imageboot.");
1073 * See if we are rooting from a nested image
1075 if(PE_parse_boot_argn("rp1", root_path
, MAXPATHLEN
) == FALSE
) {
1079 printf("%s: second level root image url is %s\n", __FUNCTION__
, root_path
);
1082 * If we fail to set up second image, it's not a given that we
1083 * can safely root off the first.
1085 error
= imageboot_mount_image(root_path
, 1);
1087 panic("Failed on second stage of imageboot.");
1091 FREE_ZONE(root_path
, MAXPATHLEN
, M_NAMEI
);
1093 DBG_TRACE("%s: exit\n", __FUNCTION__
);