chroot selhává u OpenVPN: pravidlo AppArmoru, nebo schopnost?
Přidání cesty do profilu AppArmoru nikdy neudělí CAP_SYS_CHROOT a odmítnutý chroot může pocházet ze tří oddělených vrstev. Zjistěte, kterou z nich měnit.
Démon zapisuje do logu selhání chroot a profil už vypadá velkoryse, takže lákavá oprava je rozšířit pravidlo pro cestu a restartovat. Obvykle to nic nezmění, protože chroot chrání privilegium, které profil nikdy nemohl předat. Rozhodnout, které vrstvy se dotknout, vyžaduje tři kontroly a ty jsou levné: co smí proces držet, co dovoluje politika a co odstranil spouštěč dřív, než obojí začalo mít význam.
Dvě oddělené brány a jen jedna patří AppArmoru
chroot potřebuje CAP_SYS_CHROOT v uživatelském jmenném prostoru, ve kterém proces běží. To je běžné linuxové privilegium a jádro ho ověřuje dřív, než volání s cestami cokoli udělá. Odděleně od toho může vynucující profil AppArmoru schopnost odmítnout, i když ji proces má, protože povinná politika se bere v úvahu navíc k pověřením, ne místo nich. Rozdíl je v praxi důležitý: obě vrstvy žijí v jiných souborech a obvykle je spravují jiní lidé.
Obě brány selhávají se stejnou errno. Obě vracejí EPERM a obě se v logu démona projeví jako obecná stížnost na oprávnění, a proto hádání o obsahu profilu ztrácí tolik času. Pravidlo pro cestu, které jste se chystali přidat, řídí přístup k souborům až po úspěšném chroot; na to, zda je operace vůbec povolena, nemá vliv.
Třetí brána stojí nad oběma. Pokud službu nebo obal spustily proces bez této schopnosti v jeho množině mezí, žádná změna AppArmoru ji nevrátí a přidání schopností do profilu jen dokumentuje záměr, který jádro nebude respektovat.
Přečtěte stav privilegií, než začnete editovat politiku
Začněte u běžícího procesu, ne u konfigurace, kterou považujete za aktivní. Stavový soubor vystavuje pět masek schopností a příznak no-new-privileges a ty odpovídají na různé otázky:
grep -E '^(CapInh|CapPrm|CapEff|CapBnd|CapAmb|NoNewPrivs):' /proc/$(pidof openvpn)/status
sudo aa-status | grep -i openvpnCapEff je množina, na které u volání záleží: schopnost přítomná v CapBnd, ale chybějící v CapEff je stropem povolena a momentálně se nedrží. CapAmb je důležitá, když binárka není privilegovaná v obvyklém smyslu setuid, protože ambientní schopnosti jsou způsob, jak služba udrží privilegium přes exec bez souborových schopností. CapInh drží bity, které lze dědit přes exec, ale jen když to dovoluje dědičná množina spouštěného souboru, takže bit tam sám o sobě nic nedává.
Pak ověřte, který profil je skutečně připojen. Proces může být omezen názvem profilu, který jste nečekali, zvlášť když distribuce dodává svůj unit soubor a profil společně, a čtení /proc/PID/attr/current to vyřeší jedním řádkem. Porovnat upravený soubor s profilem, který hlásí jádro, je rozdíl mezi opravou příčiny a editací souboru, který nikdo nenačítá.
Pravidlo schopnosti přidejte, jen když to říká auditní stopa
Záznamy jádra a auditu pojmenovávají vrstvu, která odmítá. Hledejte odmítnutí, které nese operaci capable a jméno sys_chroot, spolu s profilem, který ho vytvořil. Pokud takový záznam existuje, proces schopnost už držel a AppArmor ji odmítl, a cílenou změnou je pravidlo schopnosti uvnitř skutečného profilu:
capability sys_chroot,Nechte ho jako fragment v profilu, který je opravdu připojený, a klíčové slovo ověřte podle reference profilů apparmor.d, místo abyste pravidlo kopírovali z nesouvisejícího návodu. Když ho vložíte do sdíleného include, dáte ho každému omezenému programu, který ten soubor vtáhne, a přepnutí profilů do režimu stížnosti schová další odmítnutí místo vyřešení tohoto. Pravidlo v profilu odstraňuje odmítnutí politiky; privilegium nevytváří, takže proces, který nikdy neměl CAP_SYS_CHROOT v efektivní množině, selže i s tímto pravidlem.
Pokud auditní záznam neukazuje žádné odmítnutí AppArmoru, přestaňte profil editovat. Díváte se na problém s pověřeními a zbývající práce je v unit souboru nebo v rodičovském procesu, ne v jazyce politiky.
Správce služeb si drží vlastní strop
systemd nastavuje množinu mezí schopností pro každou službu a ve výchozím stavu je tato množina úzká. Co je tam vyloučeno, je procesu nedostupné bez ohledu na to, co říká profil, a proto zpevněné unity mohou selhat na operaci, která fungovala, když se démon spouštěl ručně. Příslušné direktivy se v unitu čtou snadno a snadno se přehlédnou, když chybu hlásí aplikace. Drop-in soubory dodávané balíčkem distribuce jsou obvyklým zdrojem stropu, o kterém si nikdo nepamatuje, že ho nastavoval.
Zvednout strop a udělit schopnost jsou dvě změny, ne jedna. Záznam v množině mezí říká, že proces smí schopnost držet; nepřidává ji do efektivní množiny a NoNewPrivs může zabránit tomu, aby pozdější povýšení uspělo, i když všechno ostatní sedí. Přidejte jen to, co operace potřebuje, zbytek zpevnění nechte nedotčený a odolejte zkratce udělit všechny schopnosti, aby prošlo jedno volání.
I tady záleží na pořadí. Nejprve změňte strop v unitu, ověřte, že CapEff už bit obsahuje, a teprve pak rozhodněte, zda AppArmor ještě odmítá. Když uděláte obě změny najednou, při přetrvávajícím selhání zase hádáte.
Až odmítnutí zmizí, zkontrolujte samotné vězení
Úspěšný chroot přesune kořen, takže každá cesta, které se démon potom dotkne, se vyhodnocuje uvnitř nového stromu. Chybějící konfigurace, absentující uzel zařízení nebo adresář certifikátů, který se nezkopíroval, se teď projeví jako chyba souboru, a ta chyba je problém rozvržení, ne schopnosti. Čtěte další událost, místo abyste přidávali další široké oprávnění. Přesun také mění, co znamená relativní cesta, a proto příručky pro zpevnění trvají na absolutních cestách v konfiguraci démona.
Pomáhá si také pamatovat, co chroot nedělá. Je to hranice cest, ne sandbox: proces, který si privilegium ponechá, z něj může uniknout, a proto se schopnost obvykle po volání zahazuje a proto má omezení kolem démona zůstat. Ponechat profil AppArmoru, množinu mezí schopností a omezení souborového systému pohromadě je smyslem cvičení, ne zbytek k odstranění, jakmile služba naběhne.
Rozhodovací pravidlo je krátké. Pokud auditní záznam jmenuje AppArmor, přidejte jedno pravidlo schopnosti k připojenému profilu. Pokud je efektivní množina prázdná, opravte strop v unitu a pořadí shození privilegií. Pokud profil není ten, který jste editovali, přestaňte editovat a najděte ten skutečný.