chroot misslyckas på OpenVPN: AppArmor-regel eller kapabilitet?
Att lägga till en sökväg i en AppArmor-profil ger aldrig CAP_SYS_CHROOT, och en nekad chroot kan komma från tre separata lager. Ta reda på vilket du ska ändra.
Daemonen loggar ett chroot-misslyckande och profilen ser redan generös ut, så den frestande åtgärden är att vidga en sökvägsregel och starta om. Det ändrar oftast ingenting, eftersom chroot styrs av ett privilegium som profilen aldrig kunde överlämna. Att avgöra vilket lager du ska röra kräver tre kontroller, och de är billiga: vad processen får hålla, vad policyn tillåter och vad startaren tog bort innan något av de två spelade roll.
Två separata grindar, och bara en tillhör AppArmor
chroot kräver CAP_SYS_CHROOT i det användarnamnrymd där processen körs. Det är ett vanligt Linux-privilegium som kärnan kontrollerar innan anropet gör något med sökvägar. Separat kan en AppArmor-profil i enforcing-läge neka kapabiliteten även när processen har den, eftersom den obligatoriska policyn konsulteras utöver autentiseringsuppgifterna och inte i stället för dem. Skillnaden spelar roll i praktiken: de två lagren bor i olika filer och underhålls oftast av olika personer.
Båda grindarna misslyckas med samma errno. Båda ger EPERM, och båda visar sig som ett allmänt behörighetsklagomål i daemonens logg, vilket är varför gissningar om profilens innehåll slösar så mycket tid. Sökvägsregeln du var på väg att lägga till styr filåtkomst efter att chroot har lyckats; den har ingen bäring på huruvida operationen alls är tillåten.
En tredje grind ligger uppströms om båda. Om tjänstehanteraren eller ett omslag startade processen utan kapabiliteten i sin bounding set kan ingen AppArmor-ändring lägga tillbaka den, och att lägga till kapabiliteter i profilen dokumenterar bara en avsikt som kärnan inte kommer att uppfylla.
Läs privilegieläget innan du redigerar policyn
Börja med den körande processen, inte med den konfiguration du tror är aktiv. Statusfilen visar fem kapabilitetsmasker och flaggan no-new-privileges, och de svarar på olika frågor:
grep -E '^(CapInh|CapPrm|CapEff|CapBnd|CapAmb|NoNewPrivs):' /proc/$(pidof openvpn)/status
sudo aa-status | grep -i openvpn
CapEff är den mängd som spelar roll för anropet: en kapabilitet som finns i CapBnd men saknas i CapEff är tillåten av taket och hålls inte för närvarande. CapAmb spelar roll när binären inte är privilegierad i vanlig setuid-bemärkelse, eftersom ambienta kapabiliteter är hur en tjänst behåller ett privilegium genom exec utan filkapabiliteter. CapInh håller bitar som skulle kunna ärvas genom exec, men bara när den körande filens ärvbara mängd tillåter det, så en bit där ger ingenting i sig själv.
Bekräfta sedan vilken profil som faktiskt är kopplad. En process kan vara begränsad av ett profilnamn du inte väntade dig, särskilt när en distribution levererar sin egen unit och sin egen profil tillsammans, och att läsa /proc/PID/attr/current avgör det på en rad. Att jämföra din redigerade fil med profilen som kärnan rapporterar är skillnaden mellan att åtgärda orsaken och att redigera en fil som ingen laddar.
Lägg till kapabilitetsregeln bara när spårningen säger det
Kärn- och granskningsposter namnger lagret som nekade. Leta efter en nekad åtkomst som bär operationen capable och namnet sys_chroot, tillsammans med profilen som producerade den. Om posten finns hade processen redan kapabiliteten och AppArmor nekade den, och den riktade ändringen är en kapabilitetsregel i den verkliga profilen:
capability sys_chroot,
Behåll den som ett fragment i profilen som verkligen är kopplad, och kontrollera nyckelordet mot apparmor.d-profilreferensen i stället för att kopiera en regel från en orelaterad guide. Att lägga den i en delad include ger den till varje begränsat program som läser in filen, och att växla profilen till complain-läge döljer nästa nekande i stället för att lösa detta. Profilregeln tar bort en policynekning; den skapar inte privilegium, så en process som aldrig hade CAP_SYS_CHROOT i sin effektiva mängd kommer fortfarande att misslyckas med regeln på plats.
Om granskningsposten inte visar någon AppArmor-nekning alls ska du sluta redigera profilen. Du tittar på ett autentiseringsproblem, och det återstående arbetet ligger i uniten eller i föräldraprocessen, inte i policyspråket.
Tjänstehanteraren har sitt eget tak
systemd sätter en bounding set för kapabiliteter för varje tjänst, och som standard är den mängden snäv. Allt som utesluts där är otillgängligt för processen oavsett vad profilen säger, vilket är varför härdade units kan misslyckas med en operation som fungerade när daemonen startades för hand. De relevanta direktiven är lätta att läsa i uniten och lätta att förbise när programmet självt rapporterar felet. Drop-ins som ett distributionspaket levererar är den vanliga källan till ett tak som ingen minns att de konfigurerade.
Att höja taket och att bevilja kapabiliteten är två ändringar, inte en. En post i bounding set säger att processen får hålla kapabiliteten; den lägger inte till den i den effektiva mängden, och NoNewPrivs kan hindra en senare höjning från att lyckas även när allt annat stämmer. Lägg bara till det operationen behöver, behåll resten av härdningen och stå emot genvägen att bevilja alla kapabiliteter för att få ett enda anrop att passera.
Ordningen spelar roll här också. Ändra unitens tak först, verifiera att CapEff nu innehåller biten, och avgör först därefter om AppArmor fortfarande nekar. Att göra båda ändringarna samtidigt lämnar dig gissande igen om felet kvarstår.
När nekningen försvinner, kontrollera själva fängelset
En lyckad chroot flyttar roten, så varje sökväg daemonen rör vid efteråt löses inom det nya trädet. Saknad konfiguration, en frånvarande enhetsnod eller en certifikatkatalog som inte kopierades in kommer nu att visas som ett filfel, och det felet är ett layoutproblem snarare än ett kapabilitetsproblem. Läs nästa händelse i stället för att lägga till ytterligare en bred behörighet. Flytten ändrar också vad en relativ sökväg betyder, vilket är varför härdningsguider insisterar på absoluta sökvägar i daemonens konfiguration.
Det hjälper också att minnas vad chroot inte gör. Det är en sökvägsgräns, inte en sandlåda: en process som behåller privilegiet kan ta sig ut, vilket är varför kapabiliteten normalt släpps efter anropet och varför begränsningen bör stanna kvar runt daemonen. Att behålla AppArmor-profilen, kapabiliteternas bounding set och filsystemets begränsningar tillsammans är själva poängen med övningen, inte en kvarleva att ta bort när tjänsten startar.
Beslutsregeln är kort. Om granskningsposten namnger AppArmor, lägg till en kapabilitetsregel i den kopplade profilen. Om den effektiva mängden är tom, rätta unitens tak och ordningen för privilegiesläpp. Om profilen inte är den du redigerade, sluta redigera och hitta den riktiga.