Kvifor ein OpenVPN-krok ikkje finn fila ved sida av skriptet sitt
Relative stiar i ein krok blir løyste mot prosessen, ikkje mot skriptet. Forankre dei med __file__, og kontroller deretter namnerom og identitet før løyve.
Krokar som køyrer utan feil og likevel rapporterer ei manglande fil, ser vanlegvis på feil stad, ikkje at dei sviktar i jobben sin. Relative stiar i eit skript blir løyste mot arbeidskatalogen til prosessen, og ein teneste startar med ein arbeidskatalog du ikkje har valt. Fila ved sida av skriptet og fila prosessen opnar, er berre det same når noko forankrar dei. Det gapet forklarer ein stor del av krokfeila som feilaktig blir lesne som løyveproblem.
Kontroller stien før løyva, fordi ein løyvefeil på feil fil er framleis feil fil.
Ein relativ sti blir løyst mot prosessen, ikkje mot fila
Når eit skript kallar open("policy.json"), løyser kjernen namnet mot den noverande arbeidskatalogen til prosessen. Ingenting ved plasseringa til skriptet sjølv deltek i det oppslaget. OpenVPN startar krokar frå ein katalog det vel sjølv, og valet cd kan endre han, så eit skript som er testa manuelt frå si eiga mappe, oppfører seg annleis når daemonen køyrer det. Den manuelle testen går gjennom, tenestekøyringa feilar, og logglinja nemner berre det manglande namnet.
Python legg plasseringa til skriptet open som __file__, og det er det som gjer forankring mogleg. Path(__file__).resolve().parent / "policy.json" byggjer ein sti frå fila i staden for frå prosessen. Den eine linja fjernar avhengnaden av arbeidskatalogen utan å endre noko ved privilegia.
Forankre stien med vilje, og kontroller deretter kva resolve gjer
resolve() følgjer symbolske lenkjer, så ein installasjon som lenkjer kroken på plass, forankrar ved målet til lenkja, ikkje ved katalogen som held lenkja. Det er vanlegvis det du vil ha for ei versjonert utrulling, og det er feil for eit oppsett som ventar data ved sida av den symbolske lenkja. Avgjer kva utrullinga meiner, og skriv koden deretter i staden for å oppdage skilnaden i produksjon. Path(__file__).parent utan resolve() held på den eigen katalogen til lenkja.
Viss dataa høyrer til instansen og ikkje programmet, ta ein absolutt sti frå konfigurasjonen. Hardkoding av ein plassering bind kroken til eitt vertsoppsett.
Gå gjennom fire grenser i rekkefølgje
Start med arbeidskatalogen: samanlikn WorkingDirectory, valet cd til OpenVPN og kvar innpakning som byter katalog før exec. Stadfest deretter den løyste plasseringa, fordi ei fil med same namn i ei anna utrulling kan svare på oppslaget og skjule feilen. Deretter kjem filsystemvisinga: ein chroot eller eit mount-namnerom for tenesta kan gjere ein absolutt vertssti rett og slett fråverande. Til slutt er det tilgjengeidentiteten, som er eit spørsmål skilt frå synlegheit.
ProtectHome og PrivateTmp skjuler ulike plasseringar, og ingen av dei viser seg i ei katalogliste teken frå verten. Ein sti som finst for root i eit skal, kan vere usynleg inne i namnerommet til eininga, og difor beviser testing av same kommando utanfor tenesta så lite.
Rett opp oppslaget utan å utvide tenesta
Forankring av stien løyser berre den første grensa. Det avdekkjer ikkje ein katalog tenesta skjuler, og det gjev ikkje ein uprivilegert konto tilgang til ei fil som berre er for root. Å auke script-security endrar kva skript OpenVPN vil køyre; det har ingen effekt på kvar eit relativt namn blir løyst. Å endre arbeidskatalogen for heile tenesta er breiare enn problemet, fordi kvar annan relativ sertifikat-, logg- eller hjelparsti flyttar med.
Føretrekk den smale rettinga: ein deterministisk sti i skriptet, ein eksplisitt konfigurasjonsverdi for instansdata og fileigarskap som svarar til kontoen kroken faktisk køyrer som.
Registrer bevis som namngjev grensa
Ein nyttig feilrapport inneheld tre ting: den nøyaktige stien kroken prøvde, miljøet som frambrakte han, og kva grense som avviste. Skriv ut den løyste stien og unntaket utan å dumpe innhaldet i fila. Den tredelinga skil ei feil forankring frå ein skjult mount og frå eit nekta løyve, som er tre ulike rettingar.
Påstanden om at root kan lese fila frå ein terminal svarar på eitt av dei spørsmåla og ingen av dei andre. Test i staden frå den eigne konteksten til tenesta.