Kavlji, ki delujejo brez napake in vseeno sporočajo manjkajočo datoteko, običajno gledajo na napačno mesto, ne da bi v svoji nalogi spodleteli. Relativne poti v skripti se razrešujejo glede na delovno mapo procesa, storitev pa se zažene z delovno mapo, ki si je niste izbrali. Datoteka poleg skripte in datoteka, ki jo proces odpre, sta ista stvar le, ko ju nekaj zasidra. Ta vrzel pojasni velik del odpovedi kavljev, ki se napačno berejo kot težave z dovoljenji.

Preverite pot pred dovoljenji, ker je napaka dovoljenja na napačni datoteki še vedno napačna datoteka.

Relativna pot se razrešuje glede na proces, ne glede na datoteko

Ko skripta pokliče open("policy.json"), jedro ime razreši glede na trenutno delovno mapo procesa. Nič iz lastne lokacije skripte pri tem iskanju ne sodeluje. OpenVPN začne kavlje iz mape, ki jo izbere sam, in možnost cd jo lahko spremeni, zato se skripta, preizkušena ročno iz svoje mape, obnaša drugače, ko jo zažene demon. Ročni preizkus uspe, zagon storitve spodleti, vrstica v dnevniku pa omeni samo manjkajoče ime.

Python razkrije lokacijo skripte kot __file__, in prav to omogoča zasidranje. Path(__file__).resolve().parent / "policy.json" zgradi pot iz datoteke, ne iz procesa. Ta ena vrstica odpravi odvisnost od delovne mape, ne da bi kaj spremenila pri pravicah.

Namerno zasidrajte pot, nato preverite, kaj počne resolve

resolve() sledi simbolnim povezavam, zato se namestitev, ki kavelj poveže na mesto, zasidra na cilju povezave, ne v mapi, ki povezavo vsebuje. To je pri različicah nameščanja običajno tisto, kar želite, in je napačno za postavitev, ki pričakuje podatke poleg simbolne povezave. Odločite se, kaj namestitev pomeni, in kodo napišite tako, namesto da bi razliko odkrili v produkciji. Path(__file__).parent brez resolve() obdrži lastno mapo povezave.

Če podatki pripadajo instanci in ne programu, vzemite absolutno pot iz konfiguracije. Trdo kodiranje lokacije veže kavelj na eno postavitev gostitelja.

Prehodite štiri meje po vrsti

Začnite z delovno mapo: primerjajte WorkingDirectory, možnost cd OpenVPN in katero koli ovojnico, ki zamenja mapo pred exec. Nato potrdite razrešeno lokacijo, ker lahko datoteka s podobnim imenom v drugi namestitvi odgovori na iskanje in skrije napako. Sledi pogled na datotečni sistem: chroot ali mount imenski prostor storitve lahko absolutno pot gostitelja preprosto naredita odsotno. Nazadnje identiteta dostopa, kar je vprašanje ločeno od vidnosti.

ProtectHome in PrivateTmp skrivata različne lokacije in nobeno se ne pojavi v seznamu mape, vzetem z gostitelja. Pot, ki za root obstaja v lupini, je lahko znotraj imenskega prostora enote nevidna, zato preizkušanje istega ukaza zunaj storitve dokaže tako malo.

Popravite iskanje, ne da bi razširili storitev

Zasidranje poti reši le prvo mejo. Ne razkrije mape, ki jo storitev skriva, in ne daje neprivilegiranemu računu dostopa do datoteke samo za root. Zvišanje script-security spremeni, katere skripte bo OpenVPN zagnal; na to, kje se razreši relativno ime, ne vpliva. Spreminjanje delovne mape za celo storitev je širše od težave, ker se vsaka druga relativna pot potrdila, dnevnika ali pomočnika premakne z njo.

Dajte prednost ozki popravi: deterministična pot v skripti, izrecna konfiguracijska vrednost za podatke instance in lastništvo datotek, ki ustreza računu, pod katerim kavelj dejansko teče.

Zabeležite dokaze, ki poimenujejo mejo

Uporabno poročilo o odpovedi vsebuje tri stvari: točno pot, ki jo je kavelj poskusil, okolje, ki jo je ustvarilo, in katera meja je zavrnila. Natisnite razrešeno pot in izjemo, ne da bi izlili vsebino datoteke. Ta trojica loči napačno zasidranje od skritega mounta in od zavrnitve dovoljenja, kar so trije različni popravki.

Trditev, da lahko root datoteko prebere iz terminala, odgovarja na eno od teh vprašanj in na nobeno drugo. Namesto tega preizkusite iz lastnega konteksta storitve.

Sorodni članki