Helfer startet nicht: --deep hat ihm die App-Entitlements verpasst

launchd lehnte den Start ab, ohne Absturzbericht und ohne sichtbaren Fehler:

  launchd: exited with exit reason (namespace: 9 code: 0x8) - OS_REASON_EXEC
  amfid: OnyxHelper not valid: Code=-413 "No matching profile found"
  taskgated-helper: Disallowing com.scarriffleservices.onyx.helper
                    because no eligible provisioning profiles found

Ursache war OTHER_CODE_SIGN_FLAGS = --deep, das ich anfangs für das ad-hoc
signierte MediaRemoteAdapter.framework gesetzt hatte. --deep überträgt die
Entitlements der App auf jede eingebettete Binary. Der Helfer bekam dadurch
application-identifier, weatherkit und application-groups verpasst — alles
eingeschränkte Entitlements, die ein Provisioning-Profil verlangen. Ein nacktes
Kommandozeilenprogramm kann aber keines einbetten, denn das ist eine Datei im
Bundle. Also verweigerte AMFI die Ausführung.

Für das Framework wird --deep gar nicht gebraucht: es wird von /usr/bin/perl
geladen, nicht von Onyx, und dafür ist ohnehin disable-library-validation da.

Der Helfer trägt jetzt keine Entitlements — er braucht auch keine. Ein
root-Dienst mit möglichst wenig Rechten ist genau das, was man will.

Gefunden über das Protokoll von amfid und taskgated. Der Weg dorthin führte
über zwei Ausschlüsse: der Helfer läuft direkt gestartet einwandfrei, und seine
Signatur erfüllt die Anforderung der App. Damit war klar, dass es weder an der
Binary noch an der Signatur liegt, sondern an der Umgebung.
This commit is contained in:
Guido Schmit
2026-08-10 23:01:51 +02:00
parent d73b789fb7
commit f48b29e53e
3 changed files with 750 additions and 714 deletions

View File

@@ -433,7 +433,6 @@
MARKETING_VERSION = 0.1.0; MARKETING_VERSION = 0.1.0;
MTL_ENABLE_DEBUG_INFO = NO; MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES; MTL_FAST_MATH = YES;
OTHER_CODE_SIGN_FLAGS = "--deep";
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = macosx; SDKROOT = macosx;
SWIFT_COMPILATION_MODE = wholemodule; SWIFT_COMPILATION_MODE = wholemodule;
@@ -521,7 +520,6 @@
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES; MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES; ONLY_ACTIVE_ARCH = YES;
OTHER_CODE_SIGN_FLAGS = "--deep";
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = macosx; SDKROOT = macosx;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;

View File

@@ -1,6 +1,352 @@
{ {
"sourceLanguage" : "en", "sourceLanguage" : "en",
"strings" : { "strings" : {
"%@" : {
"comment" : "A label showing the minimum RPM of a fan.",
"isCommentAutoGenerated" : true
},
"%@ U/min" : {
"comment" : "A label that shows the current speed of a fan. The argument is the current speed of the fan.",
"isCommentAutoGenerated" : true
},
"%@°" : {
"comment" : "A temperature in °C.",
"isCommentAutoGenerated" : true
},
"fans.approval.needed" : {
"extractionState" : "stale",
"localizations" : {
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "macOS wartet auf deine Freigabe. Öffne die Systemeinstellungen und erlaube den Hintergrunddienst von Onyx."
}
},
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "macOS is waiting for your approval. Open System Settings and allow Onyx's background service."
}
}
}
},
"fans.approval.open" : {
"extractionState" : "stale",
"localizations" : {
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "Systemeinstellungen öffnen"
}
},
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Open System Settings"
}
}
}
},
"fans.approval.recheck" : {
"extractionState" : "stale",
"localizations" : {
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "Erneut prüfen"
}
},
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Check again"
}
}
}
},
"fans.connecting" : {
"localizations" : {
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "Verbinde mit dem Hilfsdienst …"
}
},
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Connecting to the helper…"
}
}
}
},
"fans.hottest" : {
"extractionState" : "stale",
"localizations" : {
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "Wärmster Kern"
}
},
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Hottest core"
}
}
}
},
"fans.install" : {
"extractionState" : "stale",
"localizations" : {
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "Hilfsdienst einrichten"
}
},
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Install helper"
}
}
}
},
"fans.intro" : {
"localizations" : {
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "Onyx kann die Lüfterdrehzahl fest vorgeben, statt sie macOS zu überlassen. Dafür wird ein Hilfsdienst mit Systemrechten eingerichtet — Schreibzugriff auf den SMC geht nicht anders."
}
},
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Onyx can set a fixed fan speed instead of leaving it to macOS. This requires a helper service with system privileges — writing to the SMC is not possible otherwise."
}
}
}
},
"fans.left" : {
"extractionState" : "stale",
"localizations" : {
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "Lüfter links"
}
},
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Left fan"
}
}
}
},
"fans.mode.auto" : {
"localizations" : {
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "Automatik"
}
},
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Automatic"
}
}
}
},
"fans.mode.manual" : {
"localizations" : {
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "Manuell"
}
},
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Manual"
}
}
}
},
"fans.reason.noTemperature" : {
"extractionState" : "stale",
"localizations" : {
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "Zurück auf Automatik: keine Temperatur messbar, damit lässt sich Sicherheit nicht beurteilen."
}
},
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Back to automatic: no temperature reading, so safety cannot be judged."
}
}
}
},
"fans.reason.other" : {
"extractionState" : "stale",
"localizations" : {
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "Zurück auf Automatik."
}
},
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Back to automatic."
}
}
}
},
"fans.reason.temperature" : {
"extractionState" : "stale",
"localizations" : {
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "Zurück auf Automatik: zu heiß für eine feste Drehzahl."
}
},
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Back to automatic: too hot for a fixed speed."
}
}
}
},
"fans.reason.unknownLimits" : {
"extractionState" : "stale",
"localizations" : {
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "Zurück auf Automatik: der erlaubte Drehzahlbereich ist nicht lesbar."
}
},
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Back to automatic: the permitted speed range cannot be read."
}
}
}
},
"fans.reason.watchdog" : {
"extractionState" : "stale",
"localizations" : {
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "Zurück auf Automatik: Onyx hat sich zu lange nicht gemeldet."
}
},
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Back to automatic: Onyx went silent for too long."
}
}
}
},
"fans.right" : {
"extractionState" : "stale",
"localizations" : {
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "Lüfter rechts"
}
},
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Right fan"
}
}
}
},
"fans.safety" : {
"localizations" : {
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "Deshalb greift ein Sicherheitsnetz, das sich nicht abschalten lässt: nie unter das Minimum der Firmware, Rückfall auf Automatik ab 95 °C, Rückfall wenn Onyx sich fünf Sekunden nicht meldet, und Rückfall beim Beenden."
}
},
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "A safety net you cannot switch off is therefore always active: never below the firmware minimum, back to automatic above 95 °C, back to automatic if Onyx goes silent for five seconds, and back to automatic on quit."
}
}
}
},
"fans.safety.active" : {
"localizations" : {
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "Das Sicherheitsnetz läuft im Hilfsdienst, nicht in Onyx. Es greift auch dann, wenn Onyx abstürzt oder beendet wird."
}
},
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "The safety net runs in the helper, not in Onyx. It works even if Onyx crashes or is quit."
}
}
}
},
"fans.uninstall" : {
"extractionState" : "stale",
"localizations" : {
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "Hilfsdienst entfernen"
}
},
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Remove helper"
}
}
}
},
"fans.warning" : {
"extractionState" : "stale",
"localizations" : {
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "Eine zu niedrige Drehzahl kann den Rechner überhitzen lassen. Die Automatik regelt nach Temperatur, ein fester Wert nicht."
}
},
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "A fan speed set too low can let the Mac overheat. The automatic control adjusts to temperature; a fixed value does not."
}
}
}
},
"menu.openPanel" : { "menu.openPanel" : {
"extractionState" : "stale", "extractionState" : "stale",
"localizations" : { "localizations" : {
@@ -622,6 +968,23 @@
} }
} }
}, },
"settings.tab.fans" : {
"extractionState" : "stale",
"localizations" : {
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "Lüfter"
}
},
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Fans"
}
}
}
},
"settings.tab.menubar" : { "settings.tab.menubar" : {
"extractionState" : "stale", "extractionState" : "stale",
"localizations" : { "localizations" : {
@@ -772,342 +1135,6 @@
} }
} }
} }
},
"settings.tab.fans": {
"localizations": {
"de": {
"stringUnit": {
"state": "translated",
"value": "Lüfter"
}
},
"en": {
"stringUnit": {
"state": "translated",
"value": "Fans"
}
}
}
},
"fans.intro": {
"localizations": {
"de": {
"stringUnit": {
"state": "translated",
"value": "Onyx kann die Lüfterdrehzahl fest vorgeben, statt sie macOS zu überlassen. Dafür wird ein Hilfsdienst mit Systemrechten eingerichtet — Schreibzugriff auf den SMC geht nicht anders."
}
},
"en": {
"stringUnit": {
"state": "translated",
"value": "Onyx can set a fixed fan speed instead of leaving it to macOS. This requires a helper service with system privileges — writing to the SMC is not possible otherwise."
}
}
}
},
"fans.warning": {
"localizations": {
"de": {
"stringUnit": {
"state": "translated",
"value": "Eine zu niedrige Drehzahl kann den Rechner überhitzen lassen. Die Automatik regelt nach Temperatur, ein fester Wert nicht."
}
},
"en": {
"stringUnit": {
"state": "translated",
"value": "A fan speed set too low can let the Mac overheat. The automatic control adjusts to temperature; a fixed value does not."
}
}
}
},
"fans.safety": {
"localizations": {
"de": {
"stringUnit": {
"state": "translated",
"value": "Deshalb greift ein Sicherheitsnetz, das sich nicht abschalten lässt: nie unter das Minimum der Firmware, Rückfall auf Automatik ab 95 °C, Rückfall wenn Onyx sich fünf Sekunden nicht meldet, und Rückfall beim Beenden."
}
},
"en": {
"stringUnit": {
"state": "translated",
"value": "A safety net you cannot switch off is therefore always active: never below the firmware minimum, back to automatic above 95 °C, back to automatic if Onyx goes silent for five seconds, and back to automatic on quit."
}
}
}
},
"fans.install": {
"localizations": {
"de": {
"stringUnit": {
"state": "translated",
"value": "Hilfsdienst einrichten"
}
},
"en": {
"stringUnit": {
"state": "translated",
"value": "Install helper"
}
}
}
},
"fans.approval.needed": {
"localizations": {
"de": {
"stringUnit": {
"state": "translated",
"value": "macOS wartet auf deine Freigabe. Öffne die Systemeinstellungen und erlaube den Hintergrunddienst von Onyx."
}
},
"en": {
"stringUnit": {
"state": "translated",
"value": "macOS is waiting for your approval. Open System Settings and allow Onyx's background service."
}
}
}
},
"fans.approval.open": {
"localizations": {
"de": {
"stringUnit": {
"state": "translated",
"value": "Systemeinstellungen öffnen"
}
},
"en": {
"stringUnit": {
"state": "translated",
"value": "Open System Settings"
}
}
}
},
"fans.approval.recheck": {
"localizations": {
"de": {
"stringUnit": {
"state": "translated",
"value": "Erneut prüfen"
}
},
"en": {
"stringUnit": {
"state": "translated",
"value": "Check again"
}
}
}
},
"fans.connecting": {
"localizations": {
"de": {
"stringUnit": {
"state": "translated",
"value": "Verbinde mit dem Hilfsdienst …"
}
},
"en": {
"stringUnit": {
"state": "translated",
"value": "Connecting to the helper…"
}
}
}
},
"fans.hottest": {
"localizations": {
"de": {
"stringUnit": {
"state": "translated",
"value": "Wärmster Kern"
}
},
"en": {
"stringUnit": {
"state": "translated",
"value": "Hottest core"
}
}
}
},
"fans.left": {
"localizations": {
"de": {
"stringUnit": {
"state": "translated",
"value": "Lüfter links"
}
},
"en": {
"stringUnit": {
"state": "translated",
"value": "Left fan"
}
}
}
},
"fans.right": {
"localizations": {
"de": {
"stringUnit": {
"state": "translated",
"value": "Lüfter rechts"
}
},
"en": {
"stringUnit": {
"state": "translated",
"value": "Right fan"
}
}
}
},
"fans.mode.auto": {
"localizations": {
"de": {
"stringUnit": {
"state": "translated",
"value": "Automatik"
}
},
"en": {
"stringUnit": {
"state": "translated",
"value": "Automatic"
}
}
}
},
"fans.mode.manual": {
"localizations": {
"de": {
"stringUnit": {
"state": "translated",
"value": "Manuell"
}
},
"en": {
"stringUnit": {
"state": "translated",
"value": "Manual"
}
}
}
},
"fans.safety.active": {
"localizations": {
"de": {
"stringUnit": {
"state": "translated",
"value": "Das Sicherheitsnetz läuft im Hilfsdienst, nicht in Onyx. Es greift auch dann, wenn Onyx abstürzt oder beendet wird."
}
},
"en": {
"stringUnit": {
"state": "translated",
"value": "The safety net runs in the helper, not in Onyx. It works even if Onyx crashes or is quit."
}
}
}
},
"fans.uninstall": {
"localizations": {
"de": {
"stringUnit": {
"state": "translated",
"value": "Hilfsdienst entfernen"
}
},
"en": {
"stringUnit": {
"state": "translated",
"value": "Remove helper"
}
}
}
},
"fans.reason.watchdog": {
"localizations": {
"de": {
"stringUnit": {
"state": "translated",
"value": "Zurück auf Automatik: Onyx hat sich zu lange nicht gemeldet."
}
},
"en": {
"stringUnit": {
"state": "translated",
"value": "Back to automatic: Onyx went silent for too long."
}
}
}
},
"fans.reason.temperature": {
"localizations": {
"de": {
"stringUnit": {
"state": "translated",
"value": "Zurück auf Automatik: zu heiß für eine feste Drehzahl."
}
},
"en": {
"stringUnit": {
"state": "translated",
"value": "Back to automatic: too hot for a fixed speed."
}
}
}
},
"fans.reason.noTemperature": {
"localizations": {
"de": {
"stringUnit": {
"state": "translated",
"value": "Zurück auf Automatik: keine Temperatur messbar, damit lässt sich Sicherheit nicht beurteilen."
}
},
"en": {
"stringUnit": {
"state": "translated",
"value": "Back to automatic: no temperature reading, so safety cannot be judged."
}
}
}
},
"fans.reason.unknownLimits": {
"localizations": {
"de": {
"stringUnit": {
"state": "translated",
"value": "Zurück auf Automatik: der erlaubte Drehzahlbereich ist nicht lesbar."
}
},
"en": {
"stringUnit": {
"state": "translated",
"value": "Back to automatic: the permitted speed range cannot be read."
}
}
}
},
"fans.reason.other": {
"localizations": {
"de": {
"stringUnit": {
"state": "translated",
"value": "Zurück auf Automatik."
}
},
"en": {
"stringUnit": {
"state": "translated",
"value": "Back to automatic."
}
}
}
} }
}, },
"version" : "1.1" "version" : "1.1"

View File

@@ -13,9 +13,20 @@ settings:
MARKETING_VERSION: "0.1.0" MARKETING_VERSION: "0.1.0"
CURRENT_PROJECT_VERSION: "1" CURRENT_PROJECT_VERSION: "1"
ENABLE_HARDENED_RUNTIME: YES ENABLE_HARDENED_RUNTIME: YES
# Der MediaRemote-Adapter bringt ein ad-hoc signiertes Framework mit, das # KEIN --deep.
# der mit Team-Zertifikat signierte Host sonst nicht laden darf. #
OTHER_CODE_SIGN_FLAGS: "--deep" # Es überträgt die Entitlements der App auf jede eingebettete Binary. Der
# privilegierte Helfer bekam dadurch application-identifier, weatherkit und
# application-groups verpasst — allesamt eingeschränkte Entitlements, die
# ein Provisioning-Profil verlangen. Ein nacktes Kommandozeilenprogramm kann
# aber keines einbetten, also lehnte AMFI den Start ab:
#
# amfid: OnyxHelper not valid: Code=-413 "No matching profile found"
# taskgated-helper: Disallowing com.scarriffleservices.onyx.helper
# because no eligible provisioning profiles found
#
# Für das ad-hoc signierte MediaRemoteAdapter.framework wird --deep nicht
# gebraucht: dafür ist disable-library-validation da.
SWIFT_STRICT_CONCURRENCY: complete SWIFT_STRICT_CONCURRENCY: complete
# Xcode lagert im Debug-Build den Programmcode in eine eigene dylib aus # Xcode lagert im Debug-Build den Programmcode in eine eigene dylib aus
# (für SwiftUI-Vorschauen). Das Hauptprogramm ist dann nur noch ein Rumpf — # (für SwiftUI-Vorschauen). Das Hauptprogramm ist dann nur noch ein Rumpf —