sys_patch.py: Add additional preflight checks

This commit is contained in:
Mykola Grymalyuk
2022-05-06 11:04:41 -06:00
parent 0c5017a16a
commit b39f2a1d5d
6 changed files with 181 additions and 54 deletions

1
.gitignore vendored
View File

@@ -26,3 +26,4 @@ __pycache__/
/payloads/seed.plist /payloads/seed.plist
/payloads/AutoPkg-Assets.pkg /payloads/AutoPkg-Assets.pkg
/payloads/AutoPkg-Assets.pkg.zip /payloads/AutoPkg-Assets.pkg.zip
/payloads/Universal-Binaries

View File

@@ -6,6 +6,11 @@
- Add Macmini8,1 FeatureUnlock support - Add Macmini8,1 FeatureUnlock support
- Drops CPU check, supports all machines - Drops CPU check, supports all machines
- Refactor Root Patching System - Refactor Root Patching System
- Adds preflight checks validating patch set data and presence
- Adds dynamic Sandy Bridge Board ID patching
- Allows for unrestricted SMBIOS usage with `AppleIntelSNBGraphicsFB`
- Adds OpenCL downgrade for TeraScale 2
- Resolves VNC support (credit IronApple#2711)
- Add `OpenCore-Legacy-Patcher.plist` for applied patch info - Add `OpenCore-Legacy-Patcher.plist` for applied patch info
- Located under `/System/Library/CoreServices` - Located under `/System/Library/CoreServices`
- Lists patch sets applied including files installed and removed - Lists patch sets applied including files installed and removed

View File

@@ -35,3 +35,13 @@ class os_conversion:
return str((kernel - 9)) return str((kernel - 9))
else: else:
return str((f"10.{kernel - 4}")) return str((f"10.{kernel - 4}"))
def is_os_newer(source_major, source_minor, target_major, target_minor):
# Check if OS version 1 is newer than OS version 2
if source_major < target_major:
return True
elif source_major == target_major:
if source_minor < target_minor:
return True
else:
return False

View File

@@ -13,10 +13,14 @@
from data import os_data from data import os_data
def SystemPatchDictionary(os_major): def SystemPatchDictionary(os_major, os_minor):
sys_patch_dict = { sys_patch_dict = {
"Graphics": { "Graphics": {
"Non-Metal Common": { "Non-Metal Common": {
"OS Support": {
"OS Major": os_data.os_data.big_sur,
"OS Minor": 0
},
"Install": { "Install": {
"/System/Library/Extensions": { "/System/Library/Extensions": {
"IOSurface.kext": "10.15.7", "IOSurface.kext": "10.15.7",
@@ -68,6 +72,10 @@ def SystemPatchDictionary(os_major):
}, },
}, },
"Metal Common": { "Metal Common": {
"OS Support": {
"OS Major": os_data.os_data.monterey,
"OS Minor": 0
},
"Install": { "Install": {
"/System/Library/Frameworks": { "/System/Library/Frameworks": {
"OpenCL.framework": "11.6", "OpenCL.framework": "11.6",
@@ -81,6 +89,10 @@ def SystemPatchDictionary(os_major):
}, },
"Legacy GVA": { "Legacy GVA": {
"OS Support": {
"OS Major": os_data.os_data.big_sur,
"OS Minor": 0
},
"Install": { "Install": {
"/System/Library/PrivateFrameworks": { "/System/Library/PrivateFrameworks": {
"AppleGVA.framework": "10.13.6", "AppleGVA.framework": "10.13.6",
@@ -90,6 +102,10 @@ def SystemPatchDictionary(os_major):
}, },
"Nvidia Tesla": { "Nvidia Tesla": {
"OS Support": {
"OS Major": os_data.os_data.mojave,
"OS Minor": 0
},
"Install": { "Install": {
"/System/Library/Extensions": { "/System/Library/Extensions": {
"GeForceGA.bundle": "10.13.6", "GeForceGA.bundle": "10.13.6",
@@ -98,11 +114,17 @@ def SystemPatchDictionary(os_major):
"GeForceTeslaVADriver.bundle": "10.13.6", "GeForceTeslaVADriver.bundle": "10.13.6",
"NVDANV50HalTesla.kext": "10.13.6", "NVDANV50HalTesla.kext": "10.13.6",
"NVDAResmanTesla.kext": "10.13.6", "NVDAResmanTesla.kext": "10.13.6",
**({ "NVDAStartup.kext": "12.0 Beta 6" } if os_major >= os_data.os_data.monterey else {}) # Apple dropped NVDAStartup in 12.0 Beta 7 (XNU 21.1)
**({ "NVDAStartup.kext": "12.0 Beta 6" } if os_data.os_conversion.is_os_newer(os_data.os_data.monterey, 1, os_major, os_minor) else {})
}, },
}, },
}, },
"Nvidia Kepler": { "Nvidia Kepler": {
"OS Support": {
# 12.0 beta 7 (XNU 21.1)
"OS Major": os_data.os_data.monterey,
"OS Minor": 1
},
"Install": { "Install": {
"/System/Library/Extensions": { "/System/Library/Extensions": {
"GeForceAIRPlugin.bundle": "11.0 Beta 3", "GeForceAIRPlugin.bundle": "11.0 Beta 3",
@@ -118,6 +140,10 @@ def SystemPatchDictionary(os_major):
}, },
}, },
"Nvidia Web Drivers": { "Nvidia Web Drivers": {
"OS Support": {
"OS Major": os_data.os_data.mojave,
"OS Minor": 0
},
"Install": { "Install": {
"/System/Library/Extensions": { "/System/Library/Extensions": {
"NVDAStartupWeb.kext": "10.13.6", "NVDAStartupWeb.kext": "10.13.6",
@@ -141,6 +167,10 @@ def SystemPatchDictionary(os_major):
}, },
}, },
"AMD Non-Metal Common": { "AMD Non-Metal Common": {
"OS Support": {
"OS Major": os_data.os_data.mojave,
"OS Minor": 0
},
"Install": { "Install": {
"/System/Library/Extensions": { "/System/Library/Extensions": {
"AMDFramebuffer.kext": "10.13.6", "AMDFramebuffer.kext": "10.13.6",
@@ -162,6 +192,10 @@ def SystemPatchDictionary(os_major):
}, },
"AMD TeraScale 1": { "AMD TeraScale 1": {
"OS Support": {
"OS Major": os_data.os_data.mojave,
"OS Minor": 0
},
"Install": { "Install": {
"/System/Library/Extensions": { "/System/Library/Extensions": {
"AMD2400Controller.kext": "10.13.6", "AMD2400Controller.kext": "10.13.6",
@@ -175,8 +209,25 @@ def SystemPatchDictionary(os_major):
"ATIRadeonX2000VADriver.bundle": "10.13.6", "ATIRadeonX2000VADriver.bundle": "10.13.6",
}, },
}, },
"Remove": {
"/System/Library/Extensions": [
# Following removals are a work around for 0.4.3 and older root patches
# Previously TS1 and TS2 patch sets were shared, now they're split off
# Due to this, updating to 0.4.4 or newer can break kmutil linking
"AMD5000Controller.kext",
"AMD6000Controller.kext",
"AMDRadeonVADriver.bundle",
"AMDRadeonVADriver2.bundle",
"AMDRadeonX3000.kext",
"AMDRadeonX3000GLDriver.bundle",
],
},
}, },
"AMD TeraScale 2": { "AMD TeraScale 2": {
"OS Support": {
"OS Major": os_data.os_data.mojave,
"OS Minor": 0
},
"Install": { "Install": {
"/System/Library/Extensions": { "/System/Library/Extensions": {
"AMD5000Controller.kext": "10.13.6", "AMD5000Controller.kext": "10.13.6",
@@ -204,6 +255,10 @@ def SystemPatchDictionary(os_major):
}, },
}, },
"Intel Ironlake": { "Intel Ironlake": {
"OS Support": {
"OS Major": os_data.os_data.mojave,
"OS Minor": 0
},
"Install": { "Install": {
"/System/Library/Extensions": { "/System/Library/Extensions": {
"AppleIntelHDGraphics.kext": "10.13.6", "AppleIntelHDGraphics.kext": "10.13.6",
@@ -215,6 +270,10 @@ def SystemPatchDictionary(os_major):
}, },
}, },
"Intel Sandy Bridge": { "Intel Sandy Bridge": {
"OS Support": {
"OS Major": os_data.os_data.mojave,
"OS Minor": 0
},
"Install": { "Install": {
"/System/Library/Extensions": { "/System/Library/Extensions": {
"AppleIntelHD3000Graphics.kext": "10.13.6", "AppleIntelHD3000Graphics.kext": "10.13.6",
@@ -227,6 +286,10 @@ def SystemPatchDictionary(os_major):
}, },
}, },
"Intel Ivy Bridge": { "Intel Ivy Bridge": {
"OS Support": {
"OS Major": os_data.os_data.monterey,
"OS Minor": 0
},
"Processes": { "Processes": {
"defaults write com.apple.coremedia hardwareVideoDecoder -string enable": False, "defaults write com.apple.coremedia hardwareVideoDecoder -string enable": False,
}, },
@@ -245,6 +308,10 @@ def SystemPatchDictionary(os_major):
}, },
"Audio": { "Audio": {
"Legacy Realtek": { "Legacy Realtek": {
"OS Support": {
"OS Major": os_data.os_data.sierra,
"OS Minor": 0
},
# For iMac7,1 and iMac8,1 units with legacy Realtek HD Audio # For iMac7,1 and iMac8,1 units with legacy Realtek HD Audio
"Install": { "Install": {
"/System/Library/Extensions": { "/System/Library/Extensions": {
@@ -264,6 +331,10 @@ def SystemPatchDictionary(os_major):
}, },
# For Mac Pros with non-UGA/GOP GPUs # For Mac Pros with non-UGA/GOP GPUs
"Legacy Non-GOP": { "Legacy Non-GOP": {
"OS Support": {
"OS Major": os_data.os_data.mojave,
"OS Minor": 0
},
"Install": { "Install": {
"/System/Library/Extensions": { "/System/Library/Extensions": {
"AppleHDA.kext": "10.13.6", "AppleHDA.kext": "10.13.6",
@@ -273,6 +344,10 @@ def SystemPatchDictionary(os_major):
}, },
"Networking": { "Networking": {
"Legacy WiFi": { "Legacy WiFi": {
"OS Support": {
"OS Major": os_data.os_data.monterey,
"OS Minor": 0
},
"Install": { "Install": {
"/usr/libexec": { "/usr/libexec": {
"airportd": "11.5.2", "airportd": "11.5.2",
@@ -291,6 +366,10 @@ def SystemPatchDictionary(os_major):
}, },
"Brightness": { "Brightness": {
"Legacy Brightness": { "Legacy Brightness": {
"OS Support": {
"OS Major": os_data.os_data.high_sierra,
"OS Minor": 0
},
"Install": { "Install": {
"/System/Library/Extensions": { "/System/Library/Extensions": {
"AppleBacklight.kext": "10.12.6", "AppleBacklight.kext": "10.12.6",
@@ -309,6 +388,10 @@ def SystemPatchDictionary(os_major):
}, },
"Miscellaneous": { "Miscellaneous": {
"Legacy GMUX": { "Legacy GMUX": {
"OS Support": {
"OS Major": os_data.os_data.high_sierra,
"OS Minor": 0
},
"Install": { "Install": {
"/System/Library/Extensions/AppleGraphicsControl.kext/Contents/PlugIns": { "/System/Library/Extensions/AppleGraphicsControl.kext/Contents/PlugIns": {
"AppleMuxControl.kext": "10.12.6", "AppleMuxControl.kext": "10.12.6",
@@ -325,6 +408,10 @@ def SystemPatchDictionary(os_major):
}, },
}, },
"Legacy Keyboard Backlight": { "Legacy Keyboard Backlight": {
"OS Support": {
"OS Major": os_data.os_data.big_sur,
"OS Minor": 0
},
"Processes": { "Processes": {
"defaults write /Library/Preferences/.GlobalPreferences.plist Moraea_BacklightHack -bool true": True, "defaults write /Library/Preferences/.GlobalPreferences.plist Moraea_BacklightHack -bool true": True,
}, },

View File

@@ -50,6 +50,11 @@ class PatchSysVolume:
self.hardware_details = hardware_details self.hardware_details = hardware_details
self.init_pathing(custom_root_mount_path=None, custom_data_mount_path=None) self.init_pathing(custom_root_mount_path=None, custom_data_mount_path=None)
def __del__(self):
# Ensures that each time we're patching, we're using a clean repository
if Path(self.constants.payload_local_binaries_root_path).exists():
shutil.rmtree(self.constants.payload_local_binaries_root_path)
def init_pathing(self, custom_root_mount_path=None, custom_data_mount_path=None): def init_pathing(self, custom_root_mount_path=None, custom_data_mount_path=None):
if custom_root_mount_path and custom_data_mount_path: if custom_root_mount_path and custom_data_mount_path:
self.mount_location = custom_root_mount_path self.mount_location = custom_root_mount_path
@@ -64,41 +69,31 @@ class PatchSysVolume:
self.mount_extensions = f"{self.mount_location}/System/Library/Extensions" self.mount_extensions = f"{self.mount_location}/System/Library/Extensions"
self.mount_application_support = f"{self.mount_location_data}/Library/Application Support" self.mount_application_support = f"{self.mount_location_data}/Library/Application Support"
def find_mount_root_vol(self, patch):
def mount_root_vol(self):
# Returns boolean if Root Volume is available
self.root_mount_path = utilities.get_disk_path() self.root_mount_path = utilities.get_disk_path()
if self.root_mount_path.startswith("disk"): if self.root_mount_path.startswith("disk"):
print(f"- Found Root Volume at: {self.root_mount_path}") print(f"- Found Root Volume at: {self.root_mount_path}")
if Path(self.mount_extensions).exists(): if Path(self.mount_extensions).exists():
print("- Root Volume is already mounted") print("- Root Volume is already mounted")
if patch is True:
self.patch_root_vol()
return True return True
else: else:
self.unpatch_root_vol() if self.root_supports_snapshot is True:
return True
else:
if self.constants.detected_os > os_data.os_data.catalina and self.root_supports_snapshot is True:
print("- Mounting APFS Snapshot as writable") print("- Mounting APFS Snapshot as writable")
result = utilities.elevated(["mount", "-o", "nobrowse", "-t", "apfs", f"/dev/{self.root_mount_path}", self.mount_location], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) result = utilities.elevated(["mount", "-o", "nobrowse", "-t", "apfs", f"/dev/{self.root_mount_path}", self.mount_location], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
if result.returncode == 0: if result.returncode == 0:
print(f"- Mounted APFS Snapshot as writable at: {self.mount_location}") print(f"- Mounted APFS Snapshot as writable at: {self.mount_location}")
if Path(self.mount_extensions).exists(): if Path(self.mount_extensions).exists():
print("- Successfully mounted the Root Volume") print("- Successfully mounted the Root Volume")
if patch is True:
self.patch_root_vol()
return True return True
else: else:
self.unpatch_root_vol() print("- Root Volume appears to have unmounted unexpectedly")
return True
else: else:
print("- Failed to mount the Root Volume") print("- Unable to mount APFS Snapshot as writable")
print("- Recommend rebooting the machine and trying to patch again") print("Reason for mount failure:")
if self.constants.gui_mode is False: print(result.stdout.decode().strip())
input("- Press [ENTER] to exit: ") return False
else:
print("- Could not find root volume")
if self.constants.gui_mode is False:
input("- Press [ENTER] to exit: ")
def unpatch_root_vol(self): def unpatch_root_vol(self):
if self.constants.detected_os > os_data.os_data.catalina and self.root_supports_snapshot is True: if self.constants.detected_os > os_data.os_data.catalina and self.root_supports_snapshot is True:
@@ -248,30 +243,18 @@ class PatchSysVolume:
# Make sure SNB kexts are compatible with the host # Make sure SNB kexts are compatible with the host
if "Intel Sandy Bridge" in required_patches: if "Intel Sandy Bridge" in required_patches:
if self.computer.reported_board_id not in self.constants.sandy_board_id_stock: self.snb_board_id_patch(source_files_path)
print(f"- Found unspported Board ID {self.computer.reported_board_id}, performing AppleIntelSNBGraphicsFB bin patching")
board_to_patch = generate_smbios.determine_best_board_id_for_sandy(self.computer.reported_board_id, self.computer.gpus)
print(f"- Replacing {board_to_patch} with {self.computer.reported_board_id}")
board_to_patch_hex = bytes.fromhex(board_to_patch.encode('utf-8').hex())
reported_board_hex = bytes.fromhex(self.computer.reported_board_id.encode('utf-8').hex())
if len(board_to_patch_hex) != len(reported_board_hex):
print(f"- Error: Board ID {self.computer.reported_board_id} is not the same length as {board_to_patch}")
raise Exception("Host's Board ID is not the same length as the kext's Board ID, cannot patch!!!")
else:
path = source_files_path + "10.13.6/System/Library/Extensions/AppleIntelSNBGraphicsFB.kext/Contents/MacOS/AppleIntelSNBGraphicsFB"
if Path(path).exists():
with open(path, 'rb') as f:
data = f.read()
data = data.replace(board_to_patch_hex, reported_board_hex)
with open(path, 'wb') as f:
f.write(data)
else:
raise Exception("Failed to find AppleIntelSNBGraphicsFB.kext, cannot patch!!!")
# Check all the files are present
for patch in required_patches: for patch in required_patches:
# Check if the patch sets support the current OS
if required_patches[patch]["OS Support"]["OS Major"] > self.constants.detected_os:
print(f"Patch set OS Major check: {required_patches[patch]['OS Support']['OS Major']} < {self.constants.detected_os}")
raise Exception("This patchset is not supported on this version of macOS!")
elif required_patches[patch]["OS Support"]["OS Minor"] > self.constants.detected_os_minor:
print(f"Patch set OS Minor check: {required_patches[patch]['OS Support']['OS Minor']} < {self.constants.detected_os_minor}")
raise Exception("This patchset is not supported on this version of macOS!")
# Check if all files are present
for method_type in ["Install", "Install Non-Root"]: for method_type in ["Install", "Install Non-Root"]:
if method_type in required_patches[patch]: if method_type in required_patches[patch]:
for install_patch_directory in required_patches[patch][method_type]: for install_patch_directory in required_patches[patch][method_type]:
@@ -331,6 +314,35 @@ class PatchSysVolume:
utilities.process_status(utilities.elevated(chown_args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)) utilities.process_status(utilities.elevated(chown_args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
def snb_board_id_patch(self, source_files_path):
# AppleIntelSNBGraphicsFB hard codes the supported Board IDs for Sandy Bridge iGPUs
# Because of this, the kext errors out on unsupported systems
# This function simply patches in a supported Board ID, using 'determine_best_board_id_for_sandy()'
# to supplement the ideal Board ID
if self.computer.reported_board_id not in self.constants.sandy_board_id_stock:
print(f"- Found unspported Board ID {self.computer.reported_board_id}, performing AppleIntelSNBGraphicsFB bin patching")
board_to_patch = generate_smbios.determine_best_board_id_for_sandy(self.computer.reported_board_id, self.computer.gpus)
print(f"- Replacing {board_to_patch} with {self.computer.reported_board_id}")
board_to_patch_hex = bytes.fromhex(board_to_patch.encode('utf-8').hex())
reported_board_hex = bytes.fromhex(self.computer.reported_board_id.encode('utf-8').hex())
if len(board_to_patch_hex) != len(reported_board_hex):
print(f"- Error: Board ID {self.computer.reported_board_id} is not the same length as {board_to_patch}")
raise Exception("Host's Board ID is not the same length as the kext's Board ID, cannot patch!!!")
else:
path = source_files_path + "/10.13.6/System/Library/Extensions/AppleIntelSNBGraphicsFB.kext/Contents/MacOS/AppleIntelSNBGraphicsFB"
if Path(path).exists():
with open(path, 'rb') as f:
data = f.read()
data = data.replace(board_to_patch_hex, reported_board_hex)
with open(path, 'wb') as f:
f.write(data)
else:
print(f"- Error: Could not find {path}")
raise Exception("Failed to find AppleIntelSNBGraphicsFB.kext, cannot patch!!!")
def check_files(self): def check_files(self):
if Path(self.constants.payload_local_binaries_root_path).exists(): if Path(self.constants.payload_local_binaries_root_path).exists():
print("- Found local Apple Binaries") print("- Found local Apple Binaries")
@@ -389,7 +401,14 @@ class PatchSysVolume:
if sys_patch_detect.detect_root_patch(self.computer.real_model, self.constants).verify_patch_allowed(print_errors=not self.constants.wxpython_variant) is True: if sys_patch_detect.detect_root_patch(self.computer.real_model, self.constants).verify_patch_allowed(print_errors=not self.constants.wxpython_variant) is True:
print("- Patcher is capable of patching") print("- Patcher is capable of patching")
if self.check_files(): if self.check_files():
self.find_mount_root_vol(True) if self.mount_root_vol() is True:
self.patch_root_vol()
if self.constants.gui_mode is False:
input("\nPress [ENTER] to return to the main menu")
else:
print("- Recommend rebooting the machine and trying to patch again")
if self.constants.gui_mode is False:
input("- Press [ENTER] to exit: ")
elif self.constants.gui_mode is False: elif self.constants.gui_mode is False:
input("\nPress [ENTER] to return to the main menu: ") input("\nPress [ENTER] to return to the main menu: ")
@@ -399,8 +418,13 @@ class PatchSysVolume:
def start_unpatch(self): def start_unpatch(self):
print("- Starting Unpatch Process") print("- Starting Unpatch Process")
if sys_patch_detect.detect_root_patch(self.computer.real_model, self.constants).verify_patch_allowed(print_errors=True) is True: if sys_patch_detect.detect_root_patch(self.computer.real_model, self.constants).verify_patch_allowed(print_errors=True) is True:
self.find_mount_root_vol(False) if self.mount_root_vol() is True:
self.unpatch_root_vol()
if self.constants.gui_mode is False: if self.constants.gui_mode is False:
input("\nPress [ENTER] to return to the main menu") input("\nPress [ENTER] to return to the main menu")
else:
print("- Recommend rebooting the machine and trying to patch again")
if self.constants.gui_mode is False:
input("- Press [ENTER] to exit: ")
elif self.constants.gui_mode is False: elif self.constants.gui_mode is False:
input("\nPress [ENTER] to return to the main menu") input("\nPress [ENTER] to return to the main menu")

View File

@@ -220,7 +220,7 @@ class detect_root_patch:
return True return True
def generate_patchset(self, hardware_details): def generate_patchset(self, hardware_details):
all_hardware_patchset = sys_patch_dict.SystemPatchDictionary(self.constants.detected_os) all_hardware_patchset = sys_patch_dict.SystemPatchDictionary(self.constants.detected_os, self.constants.detected_os_minor)
required_patches = {} required_patches = {}
utilities.cls() utilities.cls()
print("- The following patches will be applied:") print("- The following patches will be applied:")