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 #if CONFIG_IMAGEBOOT_IMG4 
  51 #include <libkern/img4/interface.h> 
  52 #include <img4/img4.h> 
  55 #include <kern/kalloc.h> 
  57 #include <pexpert/pexpert.h> 
  58 #include <kern/chunklist.h> 
  60 extern struct filedesc filedesc0
; 
  62 extern int (*mountroot
)(void); 
  63 extern char rootdevice
[DEVMAXNAMESIZE
]; 
  66 typedef struct _locker_mount_args 
{ 
  67         char lmnt_path
[PATH_MAX
]; 
  68         uint16_t lmnt_preferred_hash
; 
  69 } locker_mount_args_t
; 
  72 #define DEBUG_IMAGEBOOT 0 
  75 #define DBG_TRACE(...) printf("imageboot: " __VA_ARGS__) 
  77 #define DBG_TRACE(...) do {} while(0) 
  80 #define AUTHDBG(fmt, args...) do { printf("%s: " fmt "\n", __func__, ##args); } while (0) 
  81 #define AUTHPRNT(fmt, args...) do { printf("%s: " fmt "\n", __func__, ##args); } while (0) 
  82 #define kfree_safe(x) do { if ((x)) { kfree_addr((x)); (x) = NULL; } } while (0) 
  84 extern int di_root_image(const char *path
, char *devname
, size_t devsz
, dev_t 
*dev_p
); 
  85 extern int di_root_ramfile_buf(void *buf
, size_t bufsz
, char *devname
, size_t devsz
, dev_t 
*dev_p
); 
  87 static boolean_t 
imageboot_setup_new(imageboot_type_t type
); 
  89 vnode_t 
imgboot_get_image_file(const char *path
, off_t 
*fsize
, int *errp
); /* may be required by chunklist.c */ 
  90 int read_file(const char *path
, void **bufp
, size_t *bufszp
); /* may be required by chunklist.c */ 
  92 #define kIBFilePrefix "file://" 
  94 __private_extern__ 
int 
  95 imageboot_format_is_valid(const char *root_path
) 
  97         return strncmp(root_path
, kIBFilePrefix
, 
  98                    strlen(kIBFilePrefix
)) == 0; 
 102 vnode_get_and_drop_always(vnode_t vp
) 
 109 __private_extern__ imageboot_type_t
 
 110 imageboot_needed(void) 
 112         imageboot_type_t result 
= IMAGEBOOT_NONE
; 
 113         char *root_path 
= NULL
; 
 115         DBG_TRACE("%s: checking for presence of root path\n", __FUNCTION__
); 
 117         MALLOC_ZONE(root_path
, caddr_t
, MAXPATHLEN
, M_NAMEI
, M_WAITOK
); 
 118         if (root_path 
== NULL
) { 
 119                 panic("%s: M_NAMEI zone exhausted", __FUNCTION__
); 
 122 #if CONFIG_LOCKERBOOT 
 123         if (PE_parse_boot_argn(IMAGEBOOT_LOCKER_ARG
, root_path
, MAXPATHLEN
)) { 
 124                 result 
= IMAGEBOOT_LOCKER
; 
 129         /* Check for first layer */ 
 130         if (!(PE_parse_boot_argn("rp0", root_path
, MAXPATHLEN
) || 
 131 #if CONFIG_IMAGEBOOT_IMG4 
 132             PE_parse_boot_argn("arp0", root_path
, MAXPATHLEN
) || 
 134             PE_parse_boot_argn("rp", root_path
, MAXPATHLEN
) || 
 135             PE_parse_boot_argn(IMAGEBOOT_ROOT_ARG
, root_path
, MAXPATHLEN
) || 
 136             PE_parse_boot_argn(IMAGEBOOT_AUTHROOT_ARG
, root_path
, MAXPATHLEN
))) { 
 140         /* Sanity-check first layer */ 
 141         if (imageboot_format_is_valid(root_path
)) { 
 142                 DBG_TRACE("%s: Found %s\n", __FUNCTION__
, root_path
); 
 147         result 
= IMAGEBOOT_DMG
; 
 149         /* Check for second layer */ 
 150         if (!(PE_parse_boot_argn("rp1", root_path
, MAXPATHLEN
) || 
 151             PE_parse_boot_argn(IMAGEBOOT_CONTAINER_ARG
, root_path
, MAXPATHLEN
))) { 
 155         /* Sanity-check second layer */ 
 156         if (imageboot_format_is_valid(root_path
)) { 
 157                 DBG_TRACE("%s: Found %s\n", __FUNCTION__
, root_path
); 
 159                 panic("%s: Invalid URL scheme for %s\n", 
 160                     __FUNCTION__
, root_path
); 
 164         FREE_ZONE(root_path
, MAXPATHLEN
, M_NAMEI
); 
 171  * Swaps in new root filesystem based on image path. 
 172  * Current root filesystem is removed from mount list and 
 173  * tagged MNTK_BACKS_ROOT, MNT_ROOTFS is cleared on it, and 
 174  * "rootvnode" is reset.  Root vnode of currentroot filesystem 
 175  * is returned with usecount (no iocount). 
 177 __private_extern__ 
int 
 178 imageboot_mount_image(const char *root_path
, int height
, imageboot_type_t type
) 
 183          * Need to stash this here since we may do a kernel_mount() on /, which will 
 184          * automatically update the rootvnode global. Note that vfs_mountroot() does 
 185          * not update that global, which is a bit weird. 
 187         vnode_t         old_rootvnode 
= rootvnode
; 
 190         boolean_t update_rootvnode 
= FALSE
; 
 192         if (type 
== IMAGEBOOT_DMG
) { 
 193                 error 
= di_root_image(root_path
, rootdevice
, DEVMAXNAMESIZE
, &dev
); 
 195                         panic("%s: di_root_image failed: %d\n", __FUNCTION__
, error
); 
 200                 printf("%s: root device 0x%x\n", __FUNCTION__
, rootdev
); 
 201                 error 
= vfs_mountroot(); 
 203                         panic("vfs_mountroot() failed.\n"); 
 206                 update_rootvnode 
= TRUE
; 
 208 #if CONFIG_LOCKERBOOT 
 209         else if (type 
== IMAGEBOOT_LOCKER
) { 
 210                 locker_mount_args_t 
*mntargs 
= kalloc(sizeof(*mntargs
)); 
 212                         panic("could not alloc mount args"); 
 215                 strlcpy(mntargs
->lmnt_path
, root_path
, sizeof(mntargs
->lmnt_path
)); 
 216                 mntargs
->lmnt_preferred_hash 
= 0; 
 218                 DBG_TRACE("%s: mounting locker: %s\n", __FUNCTION__
, root_path
); 
 219                 error 
= kernel_mount(LOCKERFS_NAME
, NULLVP
, NULLVP
, "/", 
 220                     mntargs
, sizeof(*mntargs
), 0, 0, vfs_context_kernel()); 
 222                         panic("failed to mount locker: %d", error
); 
 224                 kfree(mntargs
, sizeof(*mntargs
)); 
 226                 /* Clear the old mount association. */ 
 227                 old_rootvnode
->v_mountedhere 
= NULL
; 
 228                 rootvnode
->v_mount
->mnt_vnodecovered 
= NULL
; 
 232                 panic("invalid imageboot type: %d", type
); 
 236          * Get the vnode for '/'. 
 237          * Set fdp->fd_fd.fd_cdir to reference it. 
 239         if (VFS_ROOT(TAILQ_LAST(&mountlist
, mntlist
), &newdp
, vfs_context_kernel())) { 
 240                 panic("%s: cannot find root vnode", __FUNCTION__
); 
 242         DBG_TRACE("%s: old root fsname: %s\n", __FUNCTION__
, old_rootvnode
->v_mount
->mnt_vtable
->vfc_name
); 
 244         if (old_rootvnode 
!= NULL
) { 
 245                 /* remember the old rootvnode, but remove it from mountlist */ 
 246                 mount_t old_rootfs 
= old_rootvnode
->v_mount
; 
 248                 mount_list_remove(old_rootfs
); 
 249                 mount_lock(old_rootfs
); 
 250 #ifdef CONFIG_IMGSRC_ACCESS 
 251                 old_rootfs
->mnt_kern_flag 
|= MNTK_BACKS_ROOT
; 
 252 #endif /* CONFIG_IMGSRC_ACCESS */ 
 253                 old_rootfs
->mnt_flag 
&= ~MNT_ROOTFS
; 
 254                 mount_unlock(old_rootfs
); 
 257         /* switch to the new rootvnode */ 
 258         if (update_rootvnode
) { 
 262         new_rootfs 
= rootvnode
->v_mount
; 
 263         mount_lock(new_rootfs
); 
 264         new_rootfs
->mnt_flag 
|= MNT_ROOTFS
; 
 265         mount_unlock(new_rootfs
); 
 269         filedesc0
.fd_cdir 
= newdp
; 
 270         DBG_TRACE("%s: root switched\n", __FUNCTION__
); 
 272         if (old_rootvnode 
!= NULL
) { 
 273 #ifdef CONFIG_IMGSRC_ACCESS 
 274                 if (height 
>= 0 && PE_imgsrc_mount_supported()) { 
 275                         imgsrc_rootvnodes
[height
] = old_rootvnode
; 
 277                         vnode_get_and_drop_always(old_rootvnode
); 
 280 #pragma unused(height) 
 281                 vnode_get_and_drop_always(old_rootvnode
); 
 282 #endif /* CONFIG_IMGSRC_ACCESS */ 
 288 read_file(const char *path
, void **bufp
, size_t *bufszp
) 
 291         struct nameidata ndp 
= {}; 
 292         struct vnode 
*vp 
= NULL
; 
 296         bool doclose 
= false; 
 298         vfs_context_t ctx 
= vfs_context_kernel(); 
 299         proc_t p 
= vfs_context_proc(ctx
); 
 300         kauth_cred_t kerncred 
= vfs_context_ucred(ctx
); 
 302         NDINIT(&ndp
, LOOKUP
, OP_OPEN
, LOCKLEAF
, UIO_SYSSPACE
, CAST_USER_ADDR_T(path
), ctx
); 
 303         if ((err 
= namei(&ndp
)) != 0) { 
 304                 AUTHPRNT("namei failed (%s) - %d", path
, err
); 
 310         if ((err 
= vnode_size(vp
, &fsize
, ctx
)) != 0) { 
 311                 AUTHPRNT("failed to get vnode size of %s - %d", path
, err
); 
 315                 panic("negative file size"); 
 318         if ((err 
= VNOP_OPEN(vp
, FREAD
, ctx
)) != 0) { 
 319                 AUTHPRNT("failed to open %s - %d", path
, err
); 
 324         /* if bufsz is non-zero, cap the read at bufsz bytes */ 
 325         if (*bufszp 
&& *bufszp 
< (size_t)fsize
) { 
 335         if ((err 
= vn_rdwr(UIO_READ
, vp
, (caddr_t
)buf
, fsize
, 0, UIO_SYSSPACE
, IO_NODELOCKED
, kerncred
, &resid
, p
)) != 0) { 
 336                 AUTHPRNT("Cannot read %d bytes from %s - %d", (int)fsize
, path
, err
); 
 341                 /* didnt get everything we wanted */ 
 342                 AUTHPRNT("Short read of %d bytes from %s - %d", (int)fsize
, path
, resid
); 
 349                 VNOP_CLOSE(vp
, FREAD
, ctx
); 
 366 #if CONFIG_IMAGEBOOT_IMG4 || CONFIG_IMAGEBOOT_CHUNKLIST 
 368 imgboot_get_image_file(const char *path
, off_t 
*fsize
, int *errp
) 
 370         struct nameidata ndp 
= {}; 
 372         vfs_context_t ctx 
= vfs_context_kernel(); 
 375         NDINIT(&ndp
, LOOKUP
, OP_OPEN
, LOCKLEAF
, UIO_SYSSPACE
, CAST_USER_ADDR_T(path
), ctx
); 
 376         if ((err 
= namei(&ndp
)) != 0) { 
 377                 AUTHPRNT("Cannot find %s - error %d", path
, err
); 
 382                 if (vp
->v_type 
!= VREG
) { 
 384                         AUTHPRNT("%s it not a regular file", path
); 
 386                         if ((err 
= vnode_size(vp
, fsize
, ctx
)) != 0) { 
 387                                 AUTHPRNT("Cannot get file size of %s - error %d", path
, err
); 
 398 #endif /* CONFIG_IMAGEBOOT_CHUNKLIST || CONFIG_IMAGEBOOT_CHUNKLIST */ 
 400 #if CONFIG_IMAGEBOOT_IMG4 
 402 #define APTICKET_NAME "apticket.der" 
 405 imgboot_get_apticket_path(const char *rootpath
) 
 407         size_t plen 
= strlen(rootpath
) + sizeof(APTICKET_NAME
); 
 408         char *path 
= kalloc(plen
); 
 413                 strlcpy(path
, rootpath
, plen
); 
 414                 slash 
= strrchr(path
, '/'); 
 420                 strlcpy(slash
, APTICKET_NAME
, sizeof(APTICKET_NAME
) + 1); 
 426 authenticate_root_with_img4(const char *rootpath
) 
 436         DBG_TRACE("Check %s\n", rootpath
); 
 438         if (img4if 
== NULL
) { 
 439                 AUTHPRNT("AppleImage4 is not ready"); 
 443         ticket_path 
= imgboot_get_apticket_path(rootpath
); 
 444         if (ticket_path 
== NULL
) { 
 445                 AUTHPRNT("Cannot construct ticket path - out of memory"); 
 449         rv 
= read_file(ticket_path
, &tckbuf
, &tcksz
); 
 451                 AUTHPRNT("Cannot get a ticket from %s - %d\n", ticket_path
, rv
); 
 452                 goto out_with_ticket_path
; 
 455         DBG_TRACE("Got %d bytes of manifest from %s\n", (int)tcksz
, ticket_path
); 
 457         rv 
= img4_init(&i4
, 0, tckbuf
, tcksz
, NULL
); 
 459                 AUTHPRNT("Cannot initialise verification handle - error %d", rv
); 
 460                 goto out_with_ticket_bytes
; 
 463         vp 
= imgboot_get_image_file(rootpath
, NULL
, &rv
); 
 465                 /* Error message had been printed already */ 
 469         rv 
= img4_payload_init_with_vnode_4xnu(&i4pl
, 'rosi', vp
, I4PLF_UNWRAPPED
); 
 471                 AUTHPRNT("failed to init payload: %d", rv
); 
 475         rv 
= img4_get_trusted_external_payload(&i4
, &i4pl
, IMG4_ENVIRONMENT_PPL
, NULL
, NULL
); 
 477                 AUTHPRNT("failed to validate root image %s: %d", rootpath
, rv
); 
 480         img4_payload_destroy(&i4pl
); 
 483 out_with_ticket_bytes
: 
 485 out_with_ticket_path
: 
 486         kfree_safe(ticket_path
); 
 489 #endif /* CONFIG_IMAGEBOOT_IMG4 */ 
 493  * Attach the image at 'path' as a ramdisk and mount it as our new rootfs. 
 494  * All existing mounts are first umounted. 
 497 imageboot_mount_ramdisk(const char *path
) 
 506         /* Read our target image from disk */ 
 507         err 
= read_file(path
, &buf
, &bufsz
); 
 509                 printf("%s: failed: read_file() = %d\n", __func__
, err
); 
 512         DBG_TRACE("%s: read '%s' sz = %lu\n", __func__
, path
, bufsz
); 
 514 #if CONFIG_IMGSRC_ACCESS 
 515         /* Re-add all root mounts to the mount list in the correct order... */ 
 516         mount_list_remove(rootvnode
->v_mount
); 
 517         for (int i 
= 0; i 
< MAX_IMAGEBOOT_NESTING
; i
++) { 
 518                 struct vnode 
*vn 
= imgsrc_rootvnodes
[i
]; 
 521                         imgsrc_rootvnodes
[i
] = NULLVP
; 
 523                         mount_t mnt 
= vn
->v_mount
; 
 525                         mnt
->mnt_flag 
|= MNT_ROOTFS
; 
 533         mount_list_add(rootvnode
->v_mount
); 
 536         /* ... and unmount everything */ 
 537         vnode_get_and_drop_always(rootvnode
); 
 538         filedesc0
.fd_cdir 
= NULL
; 
 542         /* Attach the ramfs image ... */ 
 543         err 
= di_root_ramfile_buf(buf
, bufsz
, rootdevice
, DEVMAXNAMESIZE
, &dev
); 
 545                 printf("%s: failed: di_root_ramfile_buf() = %d\n", __func__
, err
); 
 549         /* ... and mount it */ 
 552         err 
= vfs_mountroot(); 
 554                 printf("%s: failed: vfs_mountroot() = %d\n", __func__
, err
); 
 558         /* Switch to new root vnode */ 
 559         if (VFS_ROOT(TAILQ_LAST(&mountlist
, mntlist
), &newdp
, vfs_context_kernel())) { 
 560                 panic("%s: cannot find root vnode", __func__
); 
 563         rootvnode
->v_flag 
|= VROOT
; 
 564         new_rootfs 
= rootvnode
->v_mount
; 
 565         mount_lock(new_rootfs
); 
 566         new_rootfs
->mnt_flag 
|= MNT_ROOTFS
; 
 567         mount_unlock(new_rootfs
); 
 571         filedesc0
.fd_cdir 
= newdp
; 
 573         DBG_TRACE("%s: root switched\n", __func__
); 
 583  * If the path is in <file://> URL format then we allocate memory and decode it, 
 584  * otherwise return the same pointer. 
 586  * Caller is expected to check if the pointers are different. 
 589 url_to_path(char *url_path
) 
 591         char *path 
= url_path
; 
 592         size_t len 
= strlen(kIBFilePrefix
); 
 594         if (strncmp(kIBFilePrefix
, url_path
, len
) == 0) { 
 595                 /* its a URL - remove the file:// prefix and percent-decode */ 
 598                 len 
= strlen(url_path
); 
 600                         /* Make a copy of the path to URL-decode */ 
 601                         path 
= kalloc(len 
+ 1); 
 603                                 panic("imageboot path allocation failed - cannot allocate %d bytes\n", (int)len
); 
 606                         strlcpy(path
, url_path
, len 
+ 1); 
 609                         panic("Bogus imageboot path URL - missing path\n"); 
 612                 DBG_TRACE("%s: root image URL <%s> becomes %s\n", __func__
, url_path
, path
); 
 619 imageboot_setup_new(imageboot_type_t type
) 
 622         char *root_path 
= NULL
; 
 624         boolean_t done 
= FALSE
; 
 625         boolean_t auth_root 
= TRUE
; 
 626         boolean_t ramdisk_root 
= FALSE
; 
 628         MALLOC_ZONE(root_path
, caddr_t
, MAXPATHLEN
, M_NAMEI
, M_WAITOK
); 
 629         assert(root_path 
!= NULL
); 
 631 #if CONFIG_LOCKERBOOT 
 632         if (type 
== IMAGEBOOT_LOCKER
) { 
 633                 if (!PE_parse_boot_argn(IMAGEBOOT_LOCKER_ARG
, root_path
, MAXPATHLEN
)) { 
 634                         panic("locker boot with no locker given"); 
 637                 DBG_TRACE("%s: root fsname: %s\n", __FUNCTION__
, rootvnode
->v_mount
->mnt_vtable
->vfc_name
); 
 640                  * The locker path is a path, not a URL, so just pass it directly to 
 641                  * imageboot_mount_image(). 
 643                 error 
= imageboot_mount_image(root_path
, 0, type
); 
 645                         panic("failed to mount system locker: %d", error
); 
 651 #endif /* CONFIG_LOCKERBOOT */ 
 653         unsigned imgboot_arg
; 
 654         if (PE_parse_boot_argn("-rootdmg-ramdisk", &imgboot_arg
, sizeof(imgboot_arg
))) { 
 658         if (PE_parse_boot_argn(IMAGEBOOT_CONTAINER_ARG
, root_path
, MAXPATHLEN
) == TRUE
) { 
 659                 printf("%s: container image url is %s\n", __FUNCTION__
, root_path
); 
 660                 error 
= imageboot_mount_image(root_path
, height
, type
); 
 662                         panic("Failed to mount container image."); 
 668         if (PE_parse_boot_argn(IMAGEBOOT_AUTHROOT_ARG
, root_path
, MAXPATHLEN
) == FALSE 
&& 
 669             PE_parse_boot_argn(IMAGEBOOT_ROOT_ARG
, root_path
, MAXPATHLEN
) == FALSE
) { 
 671                         panic("%s specified without %s or %s?\n", IMAGEBOOT_CONTAINER_ARG
, IMAGEBOOT_AUTHROOT_ARG
, IMAGEBOOT_ROOT_ARG
); 
 676         printf("%s: root image URL is '%s'\n", __func__
, root_path
); 
 679         if (auth_root 
&& (csr_check(CSR_ALLOW_ANY_RECOVERY_OS
) == 0)) { 
 680                 AUTHPRNT("CSR_ALLOW_ANY_RECOVERY_OS set, skipping root image authentication"); 
 685         /* Make a copy of the path to URL-decode */ 
 686         char *path 
= url_to_path(root_path
); 
 689 #if CONFIG_IMAGEBOOT_CHUNKLIST 
 691                 AUTHDBG("authenticating root image at %s", path
); 
 692                 error 
= authenticate_root_with_chunklist(path
); 
 694                         panic("root image authentication failed (err = %d)\n", error
); 
 696                 AUTHDBG("successfully authenticated %s", path
); 
 701                 error 
= imageboot_mount_ramdisk(path
); 
 703                 error 
= imageboot_mount_image(root_path
, height
, type
); 
 706         if (path 
!= root_path
) { 
 711                 panic("Failed to mount root image (err=%d, auth=%d, ramdisk=%d)\n", 
 712                     error
, auth_root
, ramdisk_root
); 
 715 #if CONFIG_IMAGEBOOT_CHUNKLIST 
 717                 /* check that the image version matches the running kernel */ 
 718                 AUTHDBG("checking root image version"); 
 719                 error 
= authenticate_root_version_check(); 
 721                         panic("root image version check failed"); 
 723                         AUTHDBG("root image version matches kernel"); 
 731         FREE_ZONE(root_path
, MAXPATHLEN
, M_NAMEI
); 
 735 __private_extern__ 
void 
 736 imageboot_setup(imageboot_type_t type
) 
 739         char *root_path 
= NULL
; 
 741         DBG_TRACE("%s: entry\n", __FUNCTION__
); 
 743         if (rootvnode 
== NULL
) { 
 744                 panic("imageboot_setup: rootvnode is NULL."); 
 748          * New boot-arg scheme: 
 749          *      root-dmg : the dmg that will be the root filesystem, authenticated by default. 
 750          *      auth-root-dmg : same as root-dmg. 
 751          *      container-dmg : an optional dmg that contains the root-dmg. 
 752          *  locker : the locker that will be the root filesystem -- mutually 
 753          *           exclusive with any other boot-arg. 
 755         if (imageboot_setup_new(type
)) { 
 759         MALLOC_ZONE(root_path
, caddr_t
, MAXPATHLEN
, M_NAMEI
, M_WAITOK
); 
 760         assert(root_path 
!= NULL
); 
 763          * Look for outermost disk image to root from.  If we're doing a nested boot, 
 764          * there's some sense in which the outer image never needs to be the root filesystem, 
 765          * but it does need very similar treatment: it must not be unmounted, needs a fake 
 766          * device vnode created for it, and should not show up in getfsstat() until exposed 
 767          * with MNT_IMGSRC. We just make it the temporary root. 
 769 #if CONFIG_IMAGEBOOT_IMG4 
 770         if (PE_parse_boot_argn("arp0", root_path
, MAXPATHLEN
)) { 
 771                 char *path 
= url_to_path(root_path
); 
 775                 if (authenticate_root_with_img4(path
)) { 
 776                         panic("Root image %s does not match the manifest\n", root_path
); 
 778                 if (path 
!= root_path
) { 
 782 #endif /* CONFIG_IMAGEBOOT_IMG4 */ 
 783         if ((PE_parse_boot_argn("rp", root_path
, MAXPATHLEN
) == FALSE
) && 
 784             (PE_parse_boot_argn("rp0", root_path
, MAXPATHLEN
) == FALSE
)) { 
 785                 panic("%s: no valid path to image.\n", __FUNCTION__
); 
 788         DBG_TRACE("%s: root image url is %s\n", __FUNCTION__
, root_path
); 
 790         error 
= imageboot_mount_image(root_path
, 0, type
); 
 792                 panic("Failed on first stage of imageboot."); 
 796          * See if we are rooting from a nested image 
 798         if (PE_parse_boot_argn("rp1", root_path
, MAXPATHLEN
) == FALSE
) { 
 802         printf("%s: second level root image url is %s\n", __FUNCTION__
, root_path
); 
 805          * If we fail to set up second image, it's not a given that we 
 806          * can safely root off the first. 
 808         error 
= imageboot_mount_image(root_path
, 1, type
); 
 810                 panic("Failed on second stage of imageboot."); 
 814         FREE_ZONE(root_path
, MAXPATHLEN
, M_NAMEI
); 
 816         DBG_TRACE("%s: exit\n", __FUNCTION__
);