+
+// Find the BaseSystem.dmg to be used as the initial root volume during certain
+// kinds of boots.
+// This may mount volumes and lookup vnodes.
+// The DEVELOPMENT kernel will look for BaseSystem.rooted.dmg first.
+// If it returns 0 (no error), then it also writes the absolute path to the
+// BaseSystem.dmg into its argument (which must be a char[MAXPATHLEN]).
+static
+int
+bsd_find_basesystem_dmg(char *bsdmgpath_out, bool *rooted_dmg, bool *skip_signature_check)
+{
+ int error;
+ size_t len;
+ char *dmgbasepath;
+ char *dmgpath;
+ bool allow_rooted_dmg = false;
+
+ dmgbasepath = zalloc_flags(ZV_NAMEI, Z_ZERO | Z_WAITOK);
+ dmgpath = zalloc_flags(ZV_NAMEI, Z_ZERO | Z_WAITOK);
+ vnode_t imagevp = NULLVP;
+
+#if DEVELOPMENT || DEBUG
+ allow_rooted_dmg = true;
+#endif
+
+ //must provide output bool
+ if (rooted_dmg && skip_signature_check) {
+ *rooted_dmg = false;
+ *skip_signature_check = false;
+ } else {
+ error = EINVAL;
+ goto done;
+ }
+
+ error = vfs_mount_recovery();
+ if (error) {
+ goto done;
+ }
+
+ len = strlcpy(dmgbasepath, "/System/Volumes/Recovery/", MAXPATHLEN);
+ if (len > MAXPATHLEN) {
+ error = ENAMETOOLONG;
+ goto done;
+ }
+
+ if (csr_check(CSR_ALLOW_ANY_RECOVERY_OS) == 0) {
+ *skip_signature_check = true;
+ allow_rooted_dmg = true;
+ }
+
+#if defined(__arm64__)
+ const char *boot_obj_path = IOGetBootObjectsPath();
+ if (boot_obj_path) {
+ if (boot_obj_path[0] == '/') {
+ dmgbasepath[len - 1] = '\0';
+ }
+
+ len = strlcat(dmgbasepath, boot_obj_path, MAXPATHLEN);
+ if (len > MAXPATHLEN) {
+ error = ENAMETOOLONG;
+ goto done;
+ }
+
+ len = strlcat(dmgbasepath, "/usr/standalone/firmware/", MAXPATHLEN);
+ if (len > MAXPATHLEN) {
+ error = ENAMETOOLONG;
+ goto done;
+ }
+
+ if (allow_rooted_dmg) {
+ len = strlcpy(dmgpath, dmgbasepath, MAXPATHLEN);
+ if (len > MAXPATHLEN) {
+ error = ENAMETOOLONG;
+ goto done;
+ }
+
+ len = strlcat(dmgpath, "arm64eBaseSystem.rooted.dmg", MAXPATHLEN);
+ if (len > MAXPATHLEN) {
+ error = ENAMETOOLONG;
+ goto done;
+ }
+
+ error = vnode_lookup(dmgpath, 0, &imagevp, vfs_context_kernel());
+ if (error == 0) {
+ *rooted_dmg = true;
+ *skip_signature_check = true;
+ goto done;
+ }
+ memset(dmgpath, 0, MAXPATHLEN);
+ }
+
+ len = strlcpy(dmgpath, dmgbasepath, MAXPATHLEN);
+ if (len > MAXPATHLEN) {
+ error = ENAMETOOLONG;
+ goto done;
+ }
+
+ len = strlcat(dmgpath, "arm64eBaseSystem.dmg", MAXPATHLEN);
+ if (len > MAXPATHLEN) {
+ error = ENAMETOOLONG;
+ goto done;
+ }
+
+ error = vnode_lookup(dmgpath, 0, &imagevp, vfs_context_kernel());
+ if (error == 0) {
+ goto done;
+ }
+ memset(dmgpath, 0, MAXPATHLEN);
+ dmgbasepath[strlen("/System/Volumes/Recovery/")] = '\0';
+ }
+#endif // __arm64__
+
+ const char *preboot_uuid = get_preboot_uuid();
+ if (preboot_uuid == NULL) {
+ // no preboot? bail out
+ return EINVAL;
+ }
+
+ len = strlcat(dmgbasepath, preboot_uuid, MAXPATHLEN);
+ if (len > MAXPATHLEN) {
+ error = ENAMETOOLONG;
+ goto done;
+ }
+
+ if (allow_rooted_dmg) {
+ // Try BaseSystem.rooted.dmg
+ len = strlcpy(dmgpath, dmgbasepath, MAXPATHLEN);
+ if (len > MAXPATHLEN) {
+ error = ENAMETOOLONG;
+ goto done;
+ }
+
+ len = strlcat(dmgpath, "/BaseSystem.rooted.dmg", MAXPATHLEN);
+ if (len > MAXPATHLEN) {
+ error = ENAMETOOLONG;
+ goto done;
+ }
+
+ error = vnode_lookup(dmgpath, 0, &imagevp, vfs_context_kernel());
+ if (error == 0) {
+ // we found it! success!
+ *rooted_dmg = true;
+ *skip_signature_check = true;
+ goto done;
+ }
+ }
+
+ // Try BaseSystem.dmg
+ len = strlcpy(dmgpath, dmgbasepath, MAXPATHLEN);
+ if (len > MAXPATHLEN) {
+ error = ENAMETOOLONG;
+ goto done;
+ }
+
+ len = strlcat(dmgpath, "/BaseSystem.dmg", MAXPATHLEN);
+ if (len > MAXPATHLEN) {
+ error = ENAMETOOLONG;
+ goto done;
+ }
+
+ error = vnode_lookup(dmgpath, 0, &imagevp, vfs_context_kernel());
+ if (error == 0) {
+ // success!
+ goto done;
+ }
+
+done:
+ if (error == 0) {
+ strlcpy(bsdmgpath_out, dmgpath, MAXPATHLEN);
+ } else {
+ bsd_init_kprintf("%s: error %d\n", __func__, error);
+ }
+ if (imagevp != NULLVP) {
+ vnode_put(imagevp);
+ }
+ zfree(ZV_NAMEI, dmgpath);
+ zfree(ZV_NAMEI, dmgbasepath);
+ return error;