
Vaše Mac aplikace získá přístup k mikrofonu — a pak ho při každém spuštění zapomene
GeekBye požádal o oprávnění k mikrofonu, udělili jste ho a fungovalo to. Při dalším spuštění: pryč. A aplikace se v Nastavení systému → Mikrofon vůbec neobjevila. Viníkem byla bezpečnostní funkce macOS, která aplikaci tiše spouštěla z cesty, jež mizí — tady je diagnóza a oprava pomocí jediné výzvy.
Tady je chyba, kvůli které začnete pochybovat o vlastních očích. Nainstalujete GeekBye, ten požádá o přístup k mikrofonu, kliknete na Allow a přepis funguje. Skvělé. Ukončíte ho, druhý den ráno znovu otevřete — a on zase požádá o přístup k mikrofonu. Jdete zkontrolovat Nastavení systému → Soukromí a zabezpečení → Mikrofon, abyste to opravili ručně, a GeekBye v seznamu vůbec není. Není zamítnutý. Není povolený. Prostě chybí, jako by nikdy nepožádal.
Každý jednotlivý kousek vypadal správně. Výzva byla skutečná. Oprávnění v tu chvíli fungovalo. Aplikace byla řádně podepsaná a notarizovaná se správnými řetězci použití. A přesto se oprávnění při každém spuštění vypařilo. GeekBye v2.0.6 to opravil — a hlavní příčinou je jedna z nejzáludnějších věcí, které macOS dělá pro vaši ochranu.
Funkce, která skrývala aplikaci sama před sebou
Viníkem je macOS App Translocation, bezpečnostní funkce Gatekeeperu. Když stáhnete aplikaci a spustíte ji přímo z DMG nebo ze složky ~/Downloads — kdekoli, kde je stále „v karanténě" — macOS ji ve skutečnosti nespouští odtud, kde ji vidíte. Transparentně ji zkopíruje na náhodnou cestu jen pro čtení, hluboko pod /private/var/folders/.../AppTranslocation/… a spustí tuto kopii. Je to dobrá obrana: brání škodlivému stažení v manipulaci se soubory vedle sebe.
Ale tady je ten střet. Systém oprávnění macOS (TCC — ten, který sleduje, kdo může používat váš mikrofon, kameru, obrazovku) identifikuje aplikaci podle její cesty a kódové identity. Když je aplikace translokovaná, ta cesta je náhodná a dočasná. Takže když udělíte přístup k mikrofonu, macOS poslušně zaznamená udělení — proti cestě, která při dalším spuštění nebude existovat. Znovu otevřete aplikaci, macOS ji translokuje na jinou náhodnou cestu, uvidí aplikaci, o které nemá žádný záznam, a zeptá se znovu. A protože ta fantomová cesta nikdy není stabilním umístěním, aplikace nikdy nezíská trvalý řádek v Nastavení systému → Mikrofon.
Aplikace udělovala oprávnění duchovi.
Proto na to také narazili jen někteří lidé. Pokud vaše kopie GeekBye už bydlela ve složce /Applications — protože jste ji tam přetáhli, nebo se tam dostala přes automatickou aktualizaci — není žádná karanténa, žádná translokace, stabilní cesta, a všechno zůstává dokonale zachováno. Chyba byla neviditelná pro nás i pro každého po první instalaci, přesně ten druh chyby, který přežívá nejdéle.
Oprava: dejte aplikaci opravdový domov
Protože celý problém je nestabilní cesta, oprava spočívá v tom dostat aplikaci na stabilní. v2.0.6 detekuje, když GeekBye běží translokovaně (nebo prostě běží mimo /Applications), a nabízí „Move to Applications" jedním kliknutím — pomocí volání macOS pro přemístění, které zkopíruje bundle do /Applications a odtud ho znovu spustí. Od té chvíle má aplikace pevnou identitu: oprávnění k mikrofonu zůstává, nahrávání obrazovky zůstává a GeekBye se konečně objeví v Nastavení systému, kde byste to čekali.
Výzva je v tomto ohledu zdvořilá. Nabízí Move to Applications, Not Now a Don't Ask Again — a pamatuje si poslední volbu, takže aplikace nikdy neotravuje někoho, kdo má záměrný důvod ji spouštět odjinud. Rozhodnutí, zda výzvu vůbec zobrazit, je izolováno do malých, čistých funkcí (je tento build translokovaný? je mimo /Applications? potlačil to uživatel?), takže logiku lze jednotkově testovat, aniž by bylo nutné spouštět skutečný notarizovaný build na skutečném svazku v karanténě.
Stejné vydání také zjednodušilo samotný zážitek z oprávnění. GeekBye dříve vyskakoval vlastní, na míru vyrobené okno oprávnění uvnitř aplikace — několik set řádků UI, které se snažilo reprodukovat něco, co operační systém už dělá dobře. v2.0.6 ho smazal a opřel se o nativní výzvu k oprávnění macOS, podpořenou tichým, neblokujícím banerem, který se objeví jen tehdy, když nějaké požadované oprávnění skutečně chybí. Méně kódu a chování, které uživatelé už znají, protože každá jiná Mac aplikace funguje stejně.
Část, na kterou jsem nejpyšnější: dokázali jsme to, než jsme tomu uvěřili
Bylo by snadné translokaci uhodnout a vydat opravu. Místo toho vydání nejprve přineslo spouštěcí diagnostiku: při spuštění GeekBye nyní hlásí vlastní cestu ke spustitelnému souboru a to, zda je translokovaný, zda je uvnitř /Applications a aktuální stav oprávnění k mikrofonu a obrazovce. Tato telemetrie proměnila pravděpodobnou teorii v potvrzenou — produkční data ukázala, že zasažené relace skutečně běžely z translokovaných cest mimo /Applications, přesně jak bylo předpovězeno.
Na tom pořadí záleží. „Výzva se objeví, ale oprávnění nezůstane" má několik možných vysvětlení — problém s podpisem, chybějící řetězec použití, problém s entitlementem, výstřednost databáze TCC. Vyloučili jsme příčiny na úrovni API (cesta požadavku byla prokazatelně správná), pak jsme nechali reálná data ukázat na vrstvu identity/cesty, místo abychom vydali nadějeplnou opravu a doufali, že tikety podpory ustanou.
Tři věci, které tato chyba učí
- Oprávnění, které vyzve, ale nezůstane, je problém identity, ne problém API. Pokud je kód požadavku správný a oprávnění přesto mizí, přestaňte přepisovat požadavek. Ptejte se, k jaké cestě a kódové identitě operační systém udělení váže — a zda je tato identita stabilní napříč spuštěními.
- Vydejte diagnostiku spolu s opravou (nebo před ní). Několik polí — odkud běžím, jaký je stav mých oprávnění — proměnilo kvalifikovaný odhad v ověřenou hlavní příčinu a řeklo nám přesně, kteří uživatelé jsou zasaženi. Ozvučte hranici, kterou máte v podezření, dřív, než ji záplatujete.
- Chyby, které se skrývají před vývojáři, jsou ty, které běží ve „špatném" prostředí. Ta naše bydlela ve složce
/Applicationsna každém vývojářském stroji, takže chyba byla pro nás strukturálně neviditelná, zatímco zasahovala uživatele při první instalaci. Když se hlášení nedaří reprodukovat, první otázka zní, co je jiné na tom, kde to běží, ne mýlí se uživatel.
GeekBye v2.0.6 vydal výzvu k přemístění a diagnostiku společně. Pro širší oblouk spolehlivosti, do kterého to zapadá, viz co ve skutečnosti obnáší verze 2 (v2.0.0) a proč nahrávání obrazovky zachytí špatný monitor (v2.0.10) — další chyba, která se vynořila jen ve specifickém prostředí. Pro sousední vydání o drobných detailech viz klidný software: oprava blikání a čip režimu odpovědi (v2.0.3 + v2.0.5).