kdk_handler.py: Add extra error handling to failed KDK install

This commit is contained in:
Mykola Grymalyuk
2023-02-08 12:23:25 -07:00
parent 4c4cacf114
commit 0d38bc0edf
5 changed files with 62 additions and 85 deletions

View File

@@ -1350,12 +1350,12 @@ class wx_python_gui:
logging.error(kdk_download_obj.error_msg)
error_msg = kdk_download_obj.error_msg
else:
kdk_result = kdk_obj.validate_kdk_checksum()
error_msg = kdk_obj.error_msg
kdk_result = self.kdk_obj.validate_kdk_checksum()
error_msg = self.kdk_obj.error_msg
else:
logging.error("Failed to download KDK")
logging.error(kdk_obj.error_msg)
error_msg = kdk_obj.error_msg
logging.error(self.kdk_obj.error_msg)
error_msg = self.kdk_obj.error_msg
if kdk_result is False:
# Create popup window to inform user of error

View File

@@ -256,7 +256,7 @@ class KernelDebugKitObject:
self.success = True
kdk_download_path = self.constants.kdk_download_path if override_path == "" else Path(override_path)
kdk_plist_path = Path(f"{kdk_download_path}/{KDK_INFO_PLIST}") if override_path == "" else Path(f"{Path(override_path).parent}/{KDK_INFO_PLIST}")
kdk_plist_path = Path(f"{kdk_download_path.parent}/{KDK_INFO_PLIST}") if override_path == "" else Path(f"{Path(override_path).parent}/{KDK_INFO_PLIST}")
self._generate_kdk_info_plist(kdk_plist_path)
return network_handler.DownloadObject(self.kdk_url, kdk_download_path)
@@ -278,6 +278,7 @@ class KernelDebugKitObject:
}
try:
plist_path.touch()
plistlib.dump(kdk_dict, plist_path.open("wb"), sort_keys=False)
except Exception as e:
logging.error(f"- Failed to generate KDK Info.plist: {e}")
@@ -503,6 +504,9 @@ class KernelDebugKitUtilities:
logging.warning("- Cannot install KDK, not running as root")
return False
logging.info(f"- Installing KDK package: {kdk_path.name}")
logging.info(f" - This may take a while...")
result = utilities.elevated(["installer", "-pkg", kdk_path, "-target", "/"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
if result.returncode != 0:
logging.info("- Failed to install KDK:")
@@ -529,7 +533,7 @@ class KernelDebugKitUtilities:
logging.warning("- Cannot install KDK, not running as root")
return False
logging.info(f"- Installing downloaded KDK (this may take a while)")
logging.info(f"- Extracting downloaded KDK disk image")
with tempfile.TemporaryDirectory() as mount_point:
result = subprocess.run(["hdiutil", "attach", kdk_path, "-mountpoint", mount_point, "-nobrowse"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
if result.returncode != 0:
@@ -541,22 +545,27 @@ class KernelDebugKitUtilities:
if not kdk_pkg_path.exists():
logging.warning("- Failed to find KDK package in DMG, likely corrupted!!!")
self._unmount_disk_image(mount_point)
return False
if self.install_kdk_pkg(kdk_pkg_path) is False:
self._unmount_disk_image(mount_point)
return False
self._create_backup(kdk_pkg_path, Path(f"{kdk_path.parent}/{KDK_INFO_PLIST}"))
result = subprocess.run(["hdiutil", "detach", mount_point], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
if result.returncode != 0:
# Non-fatal error
logging.info("- Failed to unmount KDK:")
logging.info(result.stdout.decode('utf-8'))
self._unmount_disk_image(mount_point)
logging.info("- Successfully installed KDK")
return True
def _unmount_disk_image(self, mount_point):
result = subprocess.run(["hdiutil", "detach", mount_point], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
if result.returncode != 0:
logging.info("- Failed to unmount KDK:")
logging.info(result.stdout.decode('utf-8'))
def _create_backup(self, kdk_path: Path, kdk_info_plist: Path):
"""

View File

@@ -113,56 +113,53 @@ class PatchSysVolume:
return False
def invoke_kdk_handler(self):
# If we're invoked, there is no KDK installed (or something went wrong)
kdk_result = False
error_msg = ""
kdk_obj = kdk_handler.KernelDebugKitObject(self.constants, self.constants.detected_os_build, self.constants.detected_os_version)
if kdk_obj.success is False:
error_msg = kdk_obj.error_msg
return kdk_result, error_msg, None
kdk_download_obj = kdk_obj.retrieve_download()
# We didn't get a download object, something's wrong
if not kdk_download_obj:
if kdk_obj.kdk_already_installed is True:
error_msg = "KDK already installed, function should not have been invoked"
return kdk_result, error_msg, None
else:
error_msg = "Could not retrieve KDK"
return kdk_result, error_msg, None
# Hold thread until download is complete
kdk_download_obj.download(spawn_thread=False)
if kdk_download_obj.download_complete is False:
error_msg = kdk_download_obj.error_msg
return kdk_result, error_msg, None
kdk_result = kdk_obj.validate_kdk_checksum()
downloaded_kdk = self.constants.kdk_download_path
return kdk_result, error_msg, downloaded_kdk
def merge_kdk_with_root(self, save_hid_cs=False):
if self.skip_root_kmutil_requirement is True:
return
if self.constants.detected_os < os_data.os_data.ventura:
return
downloaded_kdk = None
kdk_path = sys_patch_helpers.sys_patch_helpers(self.constants).determine_kdk_present(match_closest=False)
if kdk_path is None:
if not self.constants.kdk_download_path.exists():
kdk_result, error_msg, downloaded_kdk = self.invoke_kdk_handler()
if kdk_result is False:
raise Exception(f"Unable to download KDK: {error_msg}")
sys_patch_helpers.sys_patch_helpers(self.constants).install_kdk()
kdk_path = sys_patch_helpers.sys_patch_helpers(self.constants).determine_kdk_present(match_closest=True, override_build=downloaded_kdk)
if self.constants.kdk_download_path.exists():
if kdk_handler.KernelDebugKitUtilities().install_kdk_dmg(self.constants.kdk_download_path) is False:
logging.info("Failed to install KDK")
raise Exception("Failed to install KDK")
kdk_obj = kdk_handler.KernelDebugKitObject(self.constants, self.constants.detected_os_build, self.constants.detected_os_version)
if kdk_obj.success is False:
logging.info(f"Unable to get KDK info: {kdk_obj.error_msg}")
raise Exception(f"Unable to get KDK info: {kdk_obj.error_msg}")
if kdk_obj.kdk_already_installed is False:
kdk_download_obj = kdk_obj.retrieve_download()
if not kdk_download_obj:
logging.info(f"Could not retrieve KDK: {kdk_obj.error_msg}")
# Hold thread until download is complete
kdk_download_obj.download(spawn_thread=False)
if kdk_download_obj.download_complete is False:
error_msg = kdk_download_obj.error_msg
logging.info(f"Could not download KDK: {error_msg}")
raise Exception(f"Could not download KDK: {error_msg}")
if kdk_obj.validate_kdk_checksum() is False:
logging.info(f"KDK checksum validation failed: {kdk_obj.error_msg}")
raise Exception(f"KDK checksum validation failed: {kdk_obj.error_msg}")
kdk_handler.KernelDebugKitUtilities().install_kdk_dmg(self.constants.kdk_download_path)
# re-init kdk_obj to get the new kdk_installed_path
kdk_obj = kdk_handler.KernelDebugKitObject(self.constants, self.constants.detected_os_build, self.constants.detected_os_version)
if kdk_obj.success is False:
logging.info(f"Unable to get KDK info: {kdk_obj.error_msg}")
raise Exception(f"Unable to get KDK info: {kdk_obj.error_msg}")
if kdk_obj.kdk_already_installed is False:
# We shouldn't get here, but just in case
logging.warning(f"KDK was not installed, but should have been: {kdk_obj.error_msg}")
raise Exception("KDK was not installed, but should have been: {kdk_obj.error_msg}")
kdk_path = Path(kdk_obj.kdk_installed_path) if kdk_obj.kdk_installed_path != "" else None
oclp_plist = Path("/System/Library/CoreServices/OpenCore-Legacy-Patcher.plist")
if (Path(self.mount_location) / Path("System/Library/Extensions/System.kext/PlugIns/Libkern.kext/Libkern")).exists() and oclp_plist.exists():
@@ -178,7 +175,7 @@ class PatchSysVolume:
pass
if kdk_path is None:
logging.info(f"- Unable to find Kernel Debug Kit: {downloaded_kdk}")
logging.info(f"- Unable to find Kernel Debug Kit")
raise Exception("Unable to find Kernel Debug Kit")
self.kdk_path = kdk_path
logging.info(f"- Found KDK at: {kdk_path}")

View File

@@ -337,9 +337,7 @@ class detect_root_patch:
return utilities.check_kext_loaded("WhateverGreen", self.constants.detected_os)
def check_kdk(self):
if kdk_handler.KernelDebugKitObject(self.constants, self.constants.detected_os_build, self.constants.detected_os_version, passive=True).kdk_already_installed == "":
return False
return True
return kdk_handler.KernelDebugKitObject(self.constants, self.constants.detected_os_build, self.constants.detected_os_version, passive=True).kdk_already_installed
def check_sip(self):
if self.constants.detected_os > os_data.os_data.catalina:

View File

@@ -77,33 +77,6 @@ class sys_patch_helpers:
return True
return False
def install_kdk(self):
if not self.constants.kdk_download_path.exists():
return
logging.info(f"- Installing downloaded KDK (this may take a while)")
with tempfile.TemporaryDirectory() as mount_point:
utilities.process_status(subprocess.run(["hdiutil", "attach", self.constants.kdk_download_path, "-mountpoint", mount_point, "-nobrowse"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
# Due to a permissions bug in macOS, sometimes the OS will fail on a Read-only file system error
# We don't actually need to write inside the KDK DMG, however macOS will do whatever it wants
# Thus move the KDK to another location, and run the installer from there
kdk_dst_path = Path(f"{self.constants.payload_path}/KernelDebugKit.pkg")
if kdk_dst_path.exists():
utilities.process_status(utilities.elevated(["rm", kdk_dst_path], stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
utilities.process_status(subprocess.run(["cp", f"{mount_point}/KernelDebugKit.pkg", self.constants.payload_path], stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
result = utilities.elevated(["installer", "-pkg", kdk_dst_path, "-target", "/"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
if result.returncode != 0:
logging.info("- Failed to install KDK:")
logging.info(result.stdout.decode('utf-8'))
if result.stderr:
logging.info(result.stderr.decode('utf-8'))
utilities.elevated(["hdiutil", "detach", mount_point], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
raise Exception("Failed to install KDK")
utilities.process_status(utilities.elevated(["rm", kdk_dst_path], stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
utilities.elevated(["hdiutil", "detach", mount_point], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
logging.info("- Successfully installed KDK")
def disable_window_server_caching(self):
# On legacy GCN GPUs, the WindowServer cache generated creates