From d0dbf8e399f7ed10dd530a3bb41d5fa5e7c598ba Mon Sep 17 00:00:00 2001 From: Mykola Grymalyuk Date: Tue, 14 Jun 2022 15:02:01 -0600 Subject: [PATCH] sys_patch.py: Add proper KDK handling during root patching --- resources/sys_patch.py | 26 ++++++++++++++++++++++++++ resources/sys_patch_detect.py | 12 ++++-------- resources/sys_patch_helpers.py | 12 +++++++++++- 3 files changed, 41 insertions(+), 9 deletions(-) diff --git a/resources/sys_patch.py b/resources/sys_patch.py index 483e1ef8a..4cc7f5511 100644 --- a/resources/sys_patch.py +++ b/resources/sys_patch.py @@ -28,6 +28,9 @@ # Alternative to mounting via 'mount', Apple's update system uses 'mount_apfs' directly # '/sbin/mount_apfs -R /dev/disk5s5 /System/Volumes/Update/mnt1' +# With macOS Ventura, you will also need to install the KDK onto root if you plan to use kmutil +# This is because Apple removed on-disk binaries (ref: https://github.com/dortania/OpenCore-Legacy-Patcher/issues/998) +# 'sudo ditto /Library/Developer/KDKs//System /System/Volumes/Update/mnt1/System' import shutil import subprocess @@ -101,6 +104,26 @@ class PatchSysVolume: print(result.stdout.decode().strip()) return False + def merge_kdk_with_root(self): + if self.constants.detected_os < os_data.os_data.ventura: + return + kdk_path = sys_patch_helpers.sys_patch_helpers(self.constants).determine_kdk_present() + if kdk_path is None: + print("- Unable to find Kernel Debug Kit") + raise Exception("Unable to find Kernel Debug Kit") + print(f"- Found KDK at: {kdk_path}") + print("- Merging KDK with Root Volume") + utilities.elevated( + ["ditto", f"{kdk_path}/System", f"{self.mount_location}/System"], + stdout=subprocess.PIPE, stderr=subprocess.STDOUT + ) + # During reversing, we found that kmutil uses this path to determine whether the KDK was successfully merged + # Best to verify now before we cause any damage + if not (Path(self.mount_location) / Path("/System/Library/Extensions/System.kext/PlugIns/Libkern.kext/Libkern")).exists(): + print("- Unable to merge KDK with Root Volume") + raise Exception("Unable to merge KDK with Root Volume") + print("- Successfully merged KDK with Root Volume") + def unpatch_root_vol(self): if self.constants.detected_os > os_data.os_data.catalina and self.root_supports_snapshot is True: print("- Reverting to last signed APFS snapshot") @@ -292,6 +315,9 @@ class PatchSysVolume: if not Path(source_file).exists(): raise Exception(f"Failed to find {source_file}") + # Ensure KDK is properly installed + self.merge_kdk_with_root() + print("- Finished Preflight, starting patching") def install_new_file(self, source_folder, destination_folder, file_name): diff --git a/resources/sys_patch_detect.py b/resources/sys_patch_detect.py index cb5ab1ca2..d3f4205d9 100644 --- a/resources/sys_patch_detect.py +++ b/resources/sys_patch_detect.py @@ -3,8 +3,7 @@ # Used when supplying data to sys_patch.py # Copyright (C) 2020-2022, Dhinak G, Mykola Grymalyuk -from pathlib import Path -from resources import constants, device_probe, utilities +from resources import constants, device_probe, utilities, sys_patch_helpers from data import model_array, os_data, sip_data, sys_patch_dict class detect_root_patch: @@ -202,12 +201,9 @@ class detect_root_patch: return utilities.check_kext_loaded("WhateverGreen", self.constants.detected_os) def check_kdk(self): - if Path("/Library/Developer/KDKs").exists(): - for kdk_folder in Path("/Library/Developer/KDKs").iterdir(): - # We don't want to support mismatched KDKs - if self.constants.detected_os_build in kdk_folder.name: - return True - return False + if sys_patch_helpers.sys_patch_helpers(self.constants).determine_kdk_present() is None: + return False + return True def check_sip(self): if self.constants.detected_os > os_data.os_data.catalina: diff --git a/resources/sys_patch_helpers.py b/resources/sys_patch_helpers.py index f46f5b3a8..2efd5e4ec 100644 --- a/resources/sys_patch_helpers.py +++ b/resources/sys_patch_helpers.py @@ -60,4 +60,14 @@ class sys_patch_helpers: plistlib.dump(data, Path(source_path_file).open("wb"), sort_keys=False) if Path(source_path_file).exists(): return True - return False \ No newline at end of file + return False + + + def determine_kdk_present(self): + # Check if KDK is present + if Path("/Library/Developer/KDKs").exists(): + for kdk_folder in Path("/Library/Developer/KDKs").iterdir(): + # We don't want to support mismatched KDKs + if self.constants.detected_os_build in kdk_folder.name: + return kdk_folder + return None \ No newline at end of file