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 <libkern/crypto/sha2.h>
46 #include <libkern/crypto/rsa.h>
47 #include <libkern/OSKextLibPrivate.h>
49 #include <kern/kalloc.h>
51 #include <pexpert/pexpert.h>
52 #include <kern/chunklist.h>
54 extern struct filedesc filedesc0
;
56 extern int (*mountroot
)(void);
57 extern char rootdevice
[];
59 #define DEBUG_IMAGEBOOT 0
62 #define DBG_TRACE(...) printf(__VA_ARGS__)
64 #define DBG_TRACE(...) do {} while(0)
67 extern int di_root_image(const char *path
, char devname
[], dev_t
*dev_p
);
68 static boolean_t
imageboot_setup_new(void);
70 #define kIBFilePrefix "file://"
72 __private_extern__
int
73 imageboot_format_is_valid(const char *root_path
)
75 return (strncmp(root_path
, kIBFilePrefix
,
76 strlen(kIBFilePrefix
)) == 0);
80 vnode_get_and_drop_always(vnode_t vp
)
87 __private_extern__
int
88 imageboot_needed(void)
91 char *root_path
= NULL
;
93 DBG_TRACE("%s: checking for presence of root path\n", __FUNCTION__
);
95 MALLOC_ZONE(root_path
, caddr_t
, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
96 if (root_path
== NULL
)
97 panic("%s: M_NAMEI zone exhausted", __FUNCTION__
);
99 /* Check for first layer */
100 if (!(PE_parse_boot_argn("rp0", root_path
, MAXPATHLEN
) ||
101 PE_parse_boot_argn("rp", root_path
, MAXPATHLEN
) ||
102 PE_parse_boot_argn(IMAGEBOOT_ROOT_ARG
, root_path
, MAXPATHLEN
) ||
103 PE_parse_boot_argn(IMAGEBOOT_AUTHROOT_ARG
, root_path
, MAXPATHLEN
))) {
107 /* Sanity-check first layer */
108 if (imageboot_format_is_valid(root_path
)) {
109 DBG_TRACE("%s: Found %s\n", __FUNCTION__
, root_path
);
116 /* Check for second layer */
117 if (!(PE_parse_boot_argn("rp1", root_path
, MAXPATHLEN
) ||
118 PE_parse_boot_argn(IMAGEBOOT_CONTAINER_ARG
, root_path
, MAXPATHLEN
))) {
122 /* Sanity-check second layer */
123 if (imageboot_format_is_valid(root_path
)) {
124 DBG_TRACE("%s: Found %s\n", __FUNCTION__
, root_path
);
126 panic("%s: Invalid URL scheme for %s\n",
127 __FUNCTION__
, root_path
);
131 FREE_ZONE(root_path
, MAXPATHLEN
, M_NAMEI
);
138 * Swaps in new root filesystem based on image path.
139 * Current root filesystem is removed from mount list and
140 * tagged MNTK_BACKS_ROOT, MNT_ROOTFS is cleared on it, and
141 * "rootvnode" is reset. Root vnode of currentroot filesystem
142 * is returned with usecount (no iocount).
144 __private_extern__
int
145 imageboot_mount_image(const char *root_path
, int height
)
149 vnode_t old_rootvnode
= NULL
;
153 error
= di_root_image(root_path
, rootdevice
, &dev
);
155 panic("%s: di_root_image failed: %d\n", __FUNCTION__
, error
);
160 printf("%s: root device 0x%x\n", __FUNCTION__
, rootdev
);
161 error
= vfs_mountroot();
163 panic("vfs_mountroot() failed.\n");
167 * Get the vnode for '/'.
168 * Set fdp->fd_fd.fd_cdir to reference it.
170 if (VFS_ROOT(TAILQ_LAST(&mountlist
,mntlist
), &newdp
, vfs_context_kernel()))
171 panic("%s: cannot find root vnode", __FUNCTION__
);
173 if (rootvnode
!= NULL
) {
174 /* remember the old rootvnode, but remove it from mountlist */
177 old_rootvnode
= rootvnode
;
178 old_rootfs
= rootvnode
->v_mount
;
180 mount_list_remove(old_rootfs
);
182 mount_lock(old_rootfs
);
183 #ifdef CONFIG_IMGSRC_ACCESS
184 old_rootfs
->mnt_kern_flag
|= MNTK_BACKS_ROOT
;
185 #endif /* CONFIG_IMGSRC_ACCESS */
186 old_rootfs
->mnt_flag
&= ~MNT_ROOTFS
;
187 mount_unlock(old_rootfs
);
190 /* switch to the new rootvnode */
193 new_rootfs
= rootvnode
->v_mount
;
194 mount_lock(new_rootfs
);
195 new_rootfs
->mnt_flag
|= MNT_ROOTFS
;
196 mount_unlock(new_rootfs
);
200 filedesc0
.fd_cdir
= newdp
;
201 DBG_TRACE("%s: root switched\n", __FUNCTION__
);
203 if (old_rootvnode
!= NULL
) {
204 #ifdef CONFIG_IMGSRC_ACCESS
205 if (height
>= 0 && PE_imgsrc_mount_supported()) {
206 imgsrc_rootvnodes
[height
] = old_rootvnode
;
208 vnode_get_and_drop_always(old_rootvnode
);
211 height
= 0; /* keep the compiler from complaining */
212 vnode_get_and_drop_always(old_rootvnode
);
213 #endif /* CONFIG_IMGSRC_ACCESS */
220 * Authenticated root-dmg support
223 #define AUTHDBG(fmt, args...) do { printf("%s: " fmt "\n", __func__, ##args); } while (0)
224 #define AUTHPRNT(fmt, args...) do { printf("%s: " fmt "\n", __func__, ##args); } while (0)
226 #define kfree_safe(x) do { if ((x)) { kfree_addr((x)); (x) = NULL; } } while (0)
234 key_byteswap(void *_dst
, const void *_src
, size_t len
)
236 uint32_t *dst
__attribute__((align_value(1))) = _dst
;
237 const uint32_t *src
__attribute__((align_value(1))) = _src
;
239 assert(len
% sizeof(uint32_t) == 0);
241 len
= len
/ sizeof(uint32_t);
242 for (size_t i
= 0; i
< len
; i
++) {
243 dst
[len
-i
-1] = OSSwapInt32(src
[i
]);
248 read_file(const char *path
, void **bufp
, size_t *bufszp
)
251 struct nameidata ndp
= {};
252 struct vnode
*vp
= NULL
;
256 bool doclose
= false;
258 vfs_context_t ctx
= vfs_context_kernel();
259 proc_t p
= vfs_context_proc(ctx
);
260 kauth_cred_t kerncred
= vfs_context_ucred(ctx
);
262 NDINIT(&ndp
, LOOKUP
, OP_OPEN
, LOCKLEAF
, UIO_SYSSPACE
, path
, ctx
);
263 if ((err
= namei(&ndp
)) != 0) {
264 AUTHPRNT("namei failed (%s)", path
);
270 if ((err
= vnode_size(vp
, &fsize
, ctx
)) != 0) {
271 AUTHPRNT("failed to get vnode size");
275 panic("negative file size");
278 if ((err
= VNOP_OPEN(vp
, FREAD
, ctx
)) != 0) {
279 AUTHPRNT("failed to open vnode");
284 /* if bufsz is non-zero, cap the read at bufsz bytes */
285 if (*bufszp
&& *bufszp
< (size_t)fsize
) {
295 if ((err
= vn_rdwr(UIO_READ
, vp
, (caddr_t
)buf
, fsize
, 0, UIO_SYSSPACE
, IO_NODELOCKED
, kerncred
, &resid
, p
)) != 0) {
296 AUTHPRNT("vn_rdwr() failed");
301 /* didnt get everything we wanted */
302 AUTHPRNT("vn_rdwr resid = %d", resid
);
309 VNOP_CLOSE(vp
, FREAD
, ctx
);
327 validate_signature(const uint8_t *key_msb
, size_t keylen
, uint8_t *sig_msb
, size_t siglen
, uint8_t *digest
)
330 bool sig_valid
= false;
333 const uint8_t exponent
[] = { 0x01, 0x00, 0x01 };
334 uint8_t *modulus
= kalloc(keylen
);
335 rsa_pub_ctx
*rsa_ctx
= kalloc(sizeof(rsa_pub_ctx
));
336 sig
= kalloc(siglen
);
338 if (modulus
== NULL
|| rsa_ctx
== NULL
|| sig
== NULL
) {
343 bzero(rsa_ctx
, sizeof(rsa_pub_ctx
));
344 key_byteswap(modulus
, key_msb
, keylen
);
345 key_byteswap(sig
, sig_msb
, siglen
);
347 err
= rsa_make_pub(rsa_ctx
,
348 sizeof(exponent
), exponent
,
349 CHUNKLIST_PUBKEY_LEN
, modulus
);
351 AUTHPRNT("rsa_make_pub() failed");
355 err
= rsa_verify_pkcs1v15(rsa_ctx
, CC_DIGEST_OID_SHA256
,
356 SHA256_DIGEST_LENGTH
, digest
,
361 AUTHPRNT("rsa_verify() failed");
373 } else if (sig_valid
== true) {
374 return 0; /* success */
381 validate_chunklist(void *buf
, size_t len
)
386 size_t chunks_end
= 0;
387 bool valid_sig
= false;
388 struct chunklist_hdr
*hdr
= buf
;
390 if (len
< sizeof(struct chunklist_hdr
)) {
391 AUTHPRNT("no space for header");
395 /* recognized file format? */
396 if (hdr
->cl_magic
!= CHUNKLIST_MAGIC
||
397 hdr
->cl_file_ver
!= CHUNKLIST_FILE_VERSION_10
||
398 hdr
->cl_chunk_method
!= CHUNKLIST_SIGNATURE_METHOD_10
||
399 hdr
->cl_sig_method
!= CHUNKLIST_SIGNATURE_METHOD_10
) {
400 AUTHPRNT("unrecognized chunklist format");
404 /* does the chunk list fall within the bounds of the buffer? */
405 if (os_mul_and_add_overflow(hdr
->cl_chunk_count
, sizeof(struct chunklist_chunk
), hdr
->cl_chunk_offset
, &chunks_end
) ||
406 hdr
->cl_chunk_offset
< sizeof(struct chunklist_hdr
) || chunks_end
> len
) {
407 AUTHPRNT("invalid chunk_count (%llu) or chunk_offset (%llu)",
408 hdr
->cl_chunk_count
, hdr
->cl_chunk_offset
);
412 /* does the signature fall within the bounds of the buffer? */
413 if (os_add_overflow(hdr
->cl_sig_offset
, sizeof(struct chunklist_sig
), &sig_end
) ||
414 hdr
->cl_sig_offset
< sizeof(struct chunklist_hdr
) ||
415 hdr
->cl_sig_offset
< chunks_end
||
416 hdr
->cl_sig_offset
> len
) {
417 AUTHPRNT("invalid signature offset (%llu)", hdr
->cl_sig_offset
);
421 if (sig_end
> len
|| os_sub_overflow(len
, hdr
->cl_sig_offset
, &sigsz
) || sigsz
!= CHUNKLIST_SIG_LEN
) {
422 /* missing or incorrect signature size */
426 AUTHDBG("hashing chunklist");
428 /* hash the chunklist (excluding the signature) */
429 uint8_t sha_digest
[SHA256_DIGEST_LENGTH
];
431 SHA256_Init(&sha_ctx
);
432 SHA256_Update(&sha_ctx
, buf
, hdr
->cl_sig_offset
);
433 SHA256_Final(sha_digest
, &sha_ctx
);
435 AUTHDBG("validating chunklist signature against pub keys");
436 for (size_t i
= 0; i
< CHUNKLIST_NPUBKEYS
; i
++) {
437 const struct chunklist_pubkey
*key
= &chunklist_pubkeys
[i
];
438 err
= validate_signature(key
->key
, CHUNKLIST_PUBKEY_LEN
,
439 buf
+ hdr
->cl_sig_offset
, sigsz
, sha_digest
);
441 AUTHDBG("validated chunklist signature with key %lu (prod=%d)", i
, key
->isprod
);
442 valid_sig
= key
->isprod
;
443 #if IMAGEBOOT_ALLOW_DEVKEYS
445 /* allow dev keys in dev builds only */
446 AUTHDBG("*** allowing DEV key: this will fail in customer builds ***");
451 } else if (err
== INVALID_SIG
) {
452 /* try the next key */
454 goto out
; /* something bad happened */
458 /* At this point we tried all the keys: nothing went wrong but none of them
459 * signed our chunklist. */
460 AUTHPRNT("signature did not verify against any known public key");
465 } else if (valid_sig
== true) {
466 return 0; /* signed, and everything checked out */
473 validate_root_image(const char *root_path
, void *chunklist
)
476 struct chunklist_hdr
*hdr
= chunklist
;
477 struct chunklist_chunk
*chk
= NULL
;
479 struct nameidata ndp
= {};
480 struct vnode
*vp
= NULL
;
483 bool doclose
= false;
487 vfs_context_t ctx
= vfs_context_kernel();
488 kauth_cred_t kerncred
= vfs_context_ucred(ctx
);
489 proc_t p
= vfs_context_proc(ctx
);
491 AUTHDBG("validating root dmg %s", root_path
);
496 NDINIT(&ndp
, LOOKUP
, OP_OPEN
, LOCKLEAF
, UIO_SYSSPACE
, root_path
, ctx
);
497 if ((err
= namei(&ndp
)) != 0) {
498 AUTHPRNT("namei failed (%s)", root_path
);
504 if (vp
->v_type
!= VREG
) {
509 if ((err
= vnode_size(vp
, &fsize
, ctx
)) != 0) {
510 AUTHPRNT("failed to get vnode size");
514 if ((err
= VNOP_OPEN(vp
, FREAD
, ctx
)) != 0) {
515 AUTHPRNT("failed to open vnode");
521 * Iterate the chunk list and check each chunk
523 chk
= chunklist
+ hdr
->cl_chunk_offset
;
524 for (ch
= 0; ch
< hdr
->cl_chunk_count
; ch
++) {
528 /* allocate buffer based on first chunk size */
529 buf
= kalloc(chk
->chunk_size
);
534 bufsz
= chk
->chunk_size
;
537 if (chk
->chunk_size
> bufsz
) {
538 AUTHPRNT("chunk size too big");
543 err
= vn_rdwr(UIO_READ
, vp
, (caddr_t
)buf
, chk
->chunk_size
, offset
, UIO_SYSSPACE
, IO_NODELOCKED
, kerncred
, &resid
, p
);
545 AUTHPRNT("vn_rdrw fail (err = %d, resid = %d)", err
, resid
);
550 AUTHPRNT("chunk covered non-existant part of image");
554 /* calculate the SHA256 of this chunk */
555 uint8_t sha_digest
[SHA256_DIGEST_LENGTH
];
557 SHA256_Init(&sha_ctx
);
558 SHA256_Update(&sha_ctx
, buf
, chk
->chunk_size
);
559 SHA256_Final(sha_digest
, &sha_ctx
);
561 /* Check the calculated SHA matches the chunk list */
562 if (bcmp(sha_digest
, chk
->chunk_sha256
, SHA256_DIGEST_LENGTH
) != 0) {
563 AUTHPRNT("SHA mismatch on chunk %lu (offset %lld, size %u)", ch
, offset
, chk
->chunk_size
);
568 if (os_add_overflow(offset
, chk
->chunk_size
, &offset
)) {
575 if (offset
!= fsize
) {
576 AUTHPRNT("chunklist did not cover entire file (offset = %lld, fsize = %lld)", offset
, fsize
);
584 VNOP_CLOSE(vp
, FREAD
, ctx
);
595 construct_chunklist_path(const char *root_path
, char **bufp
)
601 path
= kalloc(MAXPATHLEN
);
603 AUTHPRNT("failed to allocate space for chunklist path");
608 len
= strnlen(root_path
, MAXPATHLEN
);
609 if (len
< MAXPATHLEN
&& len
> strlen(".dmg")) {
610 /* correctly terminated string with space for extension */
612 AUTHPRNT("malformed root path");
617 len
= strlcpy(path
, root_path
, MAXPATHLEN
);
618 if (len
>= MAXPATHLEN
) {
619 AUTHPRNT("root path is too long");
624 path
[len
- strlen(".dmg")] = '\0';
625 len
= strlcat(path
, ".chunklist", MAXPATHLEN
);
626 if (len
>= MAXPATHLEN
) {
627 AUTHPRNT("chunklist path is too long");
642 authenticate_root(const char *root_path
)
644 char *chunklist_path
= NULL
;
645 void *chunklist_buf
= NULL
;
646 size_t chunklist_len
= 32*1024*1024UL;
649 err
= construct_chunklist_path(root_path
, &chunklist_path
);
651 AUTHPRNT("failed creating chunklist path");
655 AUTHDBG("validating root against chunklist %s", chunklist_path
);
658 * Read and authenticate the chunklist, then validate the root image against
662 AUTHDBG("reading chunklist");
663 err
= read_file(chunklist_path
, &chunklist_buf
, &chunklist_len
);
665 AUTHPRNT("failed to read chunklist");
669 AUTHDBG("validating chunklist");
670 err
= validate_chunklist(chunklist_buf
, chunklist_len
);
672 AUTHDBG("missing or incorrect signature on chunklist");
675 AUTHPRNT("failed to validate chunklist");
678 AUTHDBG("successfully validated chunklist");
681 AUTHDBG("validating root image against chunklist");
682 err
= validate_root_image(root_path
, chunklist_buf
);
684 AUTHPRNT("failed to validate root image against chunklist (%d)", err
);
688 /* everything checked out - go ahead and mount this */
689 AUTHDBG("root image authenticated");
692 kfree_safe(chunklist_buf
);
693 kfree_safe(chunklist_path
);
697 static const uuid_t
*
698 getuuidfromheader_safe(const void *buf
, size_t bufsz
, size_t *uuidsz
)
700 const struct uuid_command
*cmd
= NULL
;
701 const kernel_mach_header_t
*mh
= buf
;
703 /* space for the header and at least one load command? */
704 if (bufsz
< sizeof(kernel_mach_header_t
) + sizeof(struct uuid_command
)) {
705 AUTHPRNT("libkern image too small");
709 /* validate the mach header */
710 if (mh
->magic
!= MH_MAGIC_64
|| (mh
->sizeofcmds
> bufsz
- sizeof(kernel_mach_header_t
))) {
711 AUTHPRNT("invalid MachO header");
715 /* iterate the load commands */
716 size_t offset
= sizeof(kernel_mach_header_t
);
717 for (size_t i
= 0; i
< mh
->ncmds
; i
++) {
720 if (cmd
->cmd
== LC_UUID
) {
721 *uuidsz
= sizeof(cmd
->uuid
);
725 if (os_add_overflow(cmd
->cmdsize
, offset
, &offset
) ||
726 offset
> bufsz
- sizeof(struct uuid_command
)) {
734 static const char *libkern_path
= "/System/Library/Extensions/System.kext/PlugIns/Libkern.kext/Libkern";
735 static const char *libkern_bundle
= "com.apple.kpi.libkern";
738 * Check that the UUID of the libkern currently loaded matches the one on disk.
741 auth_version_check(void)
745 size_t bufsz
= 4*1024*1024UL;
747 /* get the UUID of the libkern in /S/L/E */
749 err
= read_file(libkern_path
, &buf
, &bufsz
);
754 unsigned long uuidsz
= 0;
755 const uuid_t
*img_uuid
= getuuidfromheader_safe(buf
, bufsz
, &uuidsz
);
756 if (img_uuid
== NULL
|| uuidsz
!= sizeof(uuid_t
)) {
757 AUTHPRNT("invalid UUID (sz = %lu)", uuidsz
);
762 /* Get the UUID of the loaded libkern */
764 err
= OSKextGetUUIDForName(libkern_bundle
, live_uuid
);
766 AUTHPRNT("could not find loaded libkern");
770 /* ... and compare them */
771 if (bcmp(live_uuid
, img_uuid
, uuidsz
) != 0) {
772 AUTHPRNT("UUID of running libkern does not match %s", libkern_path
);
774 uuid_string_t img_uuid_str
, live_uuid_str
;
775 uuid_unparse(*img_uuid
, img_uuid_str
);
776 uuid_unparse(live_uuid
, live_uuid_str
);
777 AUTHPRNT("loaded libkern UUID = %s", live_uuid_str
);
778 AUTHPRNT("on-disk libkern UUID = %s", img_uuid_str
);
793 auth_imgboot_test(proc_t __unused ap
, struct auth_imgboot_test_args
*uap
, int32_t *retval
)
797 char path
[MAXPATHLEN
];
801 err
= copyinstr(uap
->path
, path
, MAXPATHLEN
, &len
);
805 if (len
>= MAXPATHLEN
) {
809 AUTHDBG("authenticating root image at %s", path
);
810 err
= authenticate_root(path
);
812 AUTHPRNT("root authentication FAIL (%d)", err
);
815 AUTHDBG("successfully authenticated %s", path
);
818 AUTHDBG("checking root image version");
819 err
= auth_version_check();
821 AUTHPRNT("root image version check FAIL (%d)", err
);
824 AUTHPRNT("root version check success (%d)", err
);
828 return EINVAL
; /* negative return values have special meaning */
835 imageboot_setup_new()
838 char *root_path
= NULL
;
840 boolean_t done
= FALSE
;
841 boolean_t auth_root
= FALSE
;
843 MALLOC_ZONE(root_path
, caddr_t
, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
844 assert(root_path
!= NULL
);
846 if (PE_parse_boot_argn(IMAGEBOOT_CONTAINER_ARG
, root_path
, MAXPATHLEN
) == TRUE
) {
847 printf("%s: container image url is %s\n", __FUNCTION__
, root_path
);
848 error
= imageboot_mount_image(root_path
, height
);
850 panic("Failed to mount container image.");
856 if (PE_parse_boot_argn(IMAGEBOOT_AUTHROOT_ARG
, root_path
, MAXPATHLEN
) == TRUE
) {
858 } else if (PE_parse_boot_argn(IMAGEBOOT_ROOT_ARG
, root_path
, MAXPATHLEN
) == FALSE
) {
860 panic("%s specified without %s?\n", IMAGEBOOT_CONTAINER_ARG
, IMAGEBOOT_ROOT_ARG
);
865 printf("%s: root image url is %s\n", __func__
, root_path
);
868 if (auth_root
&& (csr_check(CSR_ALLOW_ANY_RECOVERY_OS
) == 0)) {
869 AUTHPRNT("CSR_ALLOW_ANY_RECOVERY_OS set, skipping root image authentication");
875 /* Copy the path to use locally */
876 char *path_alloc
= kalloc(MAXPATHLEN
);
877 if (path_alloc
== NULL
) {
878 panic("imageboot path allocation failed\n");
881 char *path
= path_alloc
;
882 strlcpy(path
, root_path
, MAXPATHLEN
);
884 size_t len
= strlen(kIBFilePrefix
);
885 if (strncmp(kIBFilePrefix
, path
, len
) == 0) {
886 /* its a URL - remove the file:// prefix and percent-decode */
891 AUTHDBG("authenticating root image at %s", path
);
892 error
= authenticate_root(path
);
894 panic("root image authentication failed (err = %d)\n", error
);
896 AUTHDBG("successfully authenticated %s", path
);
898 kfree_safe(path_alloc
);
901 error
= imageboot_mount_image(root_path
, height
);
903 panic("Failed to mount root image.");
907 /* check that the image version matches the running kernel */
908 AUTHDBG("checking root image version");
909 error
= auth_version_check();
911 panic("root image version check failed");
913 AUTHDBG("root image version matches kernel");
920 FREE_ZONE(root_path
, MAXPATHLEN
, M_NAMEI
);
924 __private_extern__
void
928 char *root_path
= NULL
;
930 DBG_TRACE("%s: entry\n", __FUNCTION__
);
932 if (rootvnode
== NULL
) {
933 panic("imageboot_setup: rootvnode is NULL.");
937 * New boot-arg scheme:
938 * root-dmg : the dmg that will be the root filesystem.
939 * auth-root-dmg : same as root-dmg but with image authentication.
940 * container-dmg : an optional dmg that contains the root-dmg.
942 if (imageboot_setup_new()) {
946 MALLOC_ZONE(root_path
, caddr_t
, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
947 assert(root_path
!= NULL
);
950 * Look for outermost disk image to root from. If we're doing a nested boot,
951 * there's some sense in which the outer image never needs to be the root filesystem,
952 * but it does need very similar treatment: it must not be unmounted, needs a fake
953 * device vnode created for it, and should not show up in getfsstat() until exposed
954 * with MNT_IMGSRC. We just make it the temporary root.
956 if((PE_parse_boot_argn("rp", root_path
, MAXPATHLEN
) == FALSE
) &&
957 (PE_parse_boot_argn("rp0", root_path
, MAXPATHLEN
) == FALSE
)) {
958 panic("%s: no valid path to image.\n", __FUNCTION__
);
961 printf("%s: root image url is %s\n", __FUNCTION__
, root_path
);
963 error
= imageboot_mount_image(root_path
, 0);
965 panic("Failed on first stage of imageboot.");
969 * See if we are rooting from a nested image
971 if(PE_parse_boot_argn("rp1", root_path
, MAXPATHLEN
) == FALSE
) {
975 printf("%s: second level root image url is %s\n", __FUNCTION__
, root_path
);
978 * If we fail to set up second image, it's not a given that we
979 * can safely root off the first.
981 error
= imageboot_mount_image(root_path
, 1);
983 panic("Failed on second stage of imageboot.");
987 FREE_ZONE(root_path
, MAXPATHLEN
, M_NAMEI
);
989 DBG_TRACE("%s: exit\n", __FUNCTION__
);