De daemon logt een chroot-fout en het profiel ziet er al ruim uit, dus de verleidelijke oplossing is een padregel te verbreden en opnieuw te starten. Dat verandert meestal niets, omdat chroot wordt bewaakt door een privilege dat het profiel nooit kon overdragen. Om te bepalen welke laag je moet aanraken zijn drie goedkope controles nodig: wat het proces mag vasthouden, wat het beleid toestaat, en wat de starter verwijderde voordat een van beide ertoe deed.

Twee afzonderlijke poorten, en slechts één hoort bij AppArmor

chroot vereist CAP_SYS_CHROOT in de gebruikersnaamruimte waarin het proces draait. Dat is een gewoon Linux-privilege, door de kernel gecontroleerd voordat de aanroep iets met paden doet. Afzonderlijk kan een handhavend AppArmor-profiel de capability weigeren terwijl het proces die bezit, omdat verplicht beleid naast de inloggegevens wordt geraadpleegd en niet in plaats daarvan. Het onderscheid is in de praktijk belangrijk: de twee lagen leven in verschillende bestanden en worden meestal door verschillende mensen onderhouden.

Die twee poorten falen met dezelfde errno. Beide produceren EPERM, en beide verschijnen als een algemene toestemmingsklacht in het daemonlog, waardoor gissen naar de profielinhoud zoveel tijd verspilt. De padregel die je wilde toevoegen beheert de bestandstoegang nadat chroot is geslaagd; hij heeft niets te maken met de vraag of de bewerking überhaupt is toegestaan.

Een derde poort staat boven beide. Als de servicemanager of een wrapper het proces startte zonder de capability in zijn begrenzende set, kan geen enkele AppArmor-wijziging die terugzetten, en capabilities aan het profiel toevoegen documenteert alleen een bedoeling die de kernel niet zal respecteren.

Lees de privilegestatus voordat je beleid bewerkt

Begin bij het draaiende proces en niet bij de configuratie waarvan je denkt dat die actief is. Het statusbestand toont vijf capabiliteitsmaskers en de no-new-privileges-vlag, en die beantwoorden verschillende vragen:

grep -E '^(CapInh|CapPrm|CapEff|CapBnd|CapAmb|NoNewPrivs):' /proc/$(pidof openvpn)/status
sudo aa-status | grep -i openvpn

CapEff is de set die voor de aanroep telt: een capability die in CapBnd zit maar in CapEff ontbreekt, is door het plafond toegestaan en wordt nu niet gehouden. CapAmb is van belang wanneer het binaire bestand niet op de gebruikelijke setuid-manier bevoorrecht is, omdat omgevingscapabilities de manier zijn waarop een dienst een privilege over exec heen behoudt zonder bestandscapabilities. CapInh bevat bits die over exec heen geërfd kunnen worden, maar alleen wanneer de erfbare set van het uitgevoerde bestand dat toestaat, dus een bit daar geeft op zichzelf niets.

Bevestig daarna welk profiel werkelijk is gekoppeld. Een proces kan opgesloten zitten door een profielnaam die je niet verwachtte, vooral wanneer een distributie zijn eigen unitbestand en profiel samen levert, en het lezen van /proc/PID/attr/current beslist dat in één regel. Je bewerkte bestand vergelijken met het profiel dat de kernel rapporteert, is het verschil tussen de oorzaak oplossen en een bestand bewerken dat niemand laadt.

Voeg de capabiliteitsregel alleen toe wanneer het audittrail dat zegt

Kernel- en auditrecords noemen de laag die weigerde. Zoek een weigering met de bewerking capable en de naam sys_chroot, samen met het profiel dat die produceerde. Als dat record bestaat, had het proces de capability al en weigerde AppArmor, en de gerichte wijziging is een capabiliteitsregel in het echte profiel:

capability sys_chroot,

Houd hem als fragment in het profiel dat echt gekoppeld is, en controleer het sleutelwoord tegen de apparmor.d-profielreferentie in plaats van een regel uit een ongerelateerde handleiding te kopiëren. Hem in een gedeelde include zetten verleent hem aan elk opgesloten programma dat dat bestand intrekt, en het profiel naar complain-modus zetten verbergt de volgende weigering in plaats van deze op te lossen. De profielregel verwijdert een beleidsweigering; hij maakt geen privilege, dus een proces dat nooit CAP_SYS_CHROOT in zijn effectieve set had, zal met de regel nog steeds falen.

Als het auditrecord helemaal geen AppArmor-weigering toont, stop dan met het profiel te bewerken. Je kijkt naar een probleem met inloggegevens, en het resterende werk zit in het unitbestand of het ouderproces, niet in de beleidstaal.

De servicemanager houdt zijn eigen plafond

systemd stelt voor elke dienst een begrenzende capabiliteitsset in, en standaard is die set smal. Alles wat daar is uitgesloten, is voor het proces onbeschikbaar wat het profiel ook zegt, waardoor geharde units kunnen falen in een bewerking die werkte toen de daemon met de hand werd gestart. De relevante richtlijnen zijn makkelijk te lezen in de unit en makkelijk over het hoofd te zien wanneer de toepassing de fout meldt. Drop-in-bestanden van een distributiepakket zijn de gebruikelijke bron van een plafond dat niemand zich herinnert te hebben ingesteld.

Het plafond verhogen en de capability verlenen zijn twee wijzigingen, niet één. Een regel in de begrenzende set zegt dat het proces de capability mag houden; hij voegt hem niet toe aan de effectieve set, en NoNewPrivs kan een latere verhoging laten mislukken zelfs wanneer al het andere klopt. Voeg alleen toe wat de bewerking nodig heeft, houd de rest van de hardening intact, en weersta de kortere weg om elke capability te verlenen zodat één aanroep doorkomt.

Ook de volgorde is hier belangrijk. Wijzig eerst het plafond van de unit, controleer dat CapEff nu het bit bevat, en beslis pas daarna of AppArmor nog weigert. Beide wijzigingen tegelijk doen laat je weer gissen als de fout aanhoudt.

Nadat de weigering is verdwenen, controleer de gevangenis zelf

Een geslaagde chroot verplaatst de root, dus elk pad dat de daemon daarna aanraakt, wordt binnen de nieuwe boom opgelost. Ontbrekende configuratie, een afwezige apparaatnode of een certificaatmap die niet is gekopieerd, verschijnen nu als bestandsfout, en die fout is een indelingsprobleem en geen capabiliteitsprobleem. Lees de volgende gebeurtenis in plaats van nog een brede toestemming toe te voegen. De verplaatsing verandert ook wat een relatief pad betekent, waardoor hardeninggidsen aandringen op absolute paden in de daemonconfiguratie.

Het helpt ook te onthouden wat chroot niet doet. Het is een padgrens, geen sandbox: een proces dat het privilege behoudt, kan ontsnappen, waardoor de capability gewoonlijk na de aanroep wordt losgelaten en waardoor de opsluiting rond de daemon moet blijven. Het AppArmor-profiel, de begrenzende capabiliteitsset en de bestandssysteembeperkingen samen aanhouden is het doel van deze oefening, geen restant dat wordt verwijderd zodra de dienst start.

De beslisregel is kort. Als het auditrecord AppArmor noemt, voeg één capabiliteitsregel toe aan het gekoppelde profiel. Als de effectieve set leeg is, herstel het plafond van de unit en de volgorde waarin het privilege wordt losgelaten. Als het profiel niet het jouwe is, stop met bewerken en zoek het echte.

Gerelateerde artikelen