Τα άγκιστρα που εκτελούνται χωρίς σφάλμα και πάλι αναφέρουν αρχείο που λείπει συνήθως κοιτούν στο λάθος μέρος, δεν αποτυγχάνουν στο έργο τους. Οι σχετικές διαδρομές σε ένα σενάριο επιλύονται με βάση τον κατάλογο εργασίας της διεργασίας, και μια υπηρεσία ξεκινά με κατάλογο εργασίας που δεν επιλέξατε. Το αρχείο δίπλα στο σενάριο και το αρχείο που ανοίγει η διεργασία είναι το ίδιο πράγμα μόνο όταν κάτι τα αγκυρώνει. Αυτό το χάσμα εξηγεί μεγάλο μέρος των αποτυχιών αγκίστρων που διαβάζονται λανθασμένα ως προβλήματα δικαιωμάτων.

Ελέγξτε τη διαδρομή πριν από τα δικαιώματα, γιατί ένα σφάλμα δικαιωμάτων στο λάθος αρχείο παραμένει το λάθος αρχείο.

Μια σχετική διαδρομή επιλύεται με βάση τη διεργασία, όχι το αρχείο

Όταν ένα σενάριο καλεί open("policy.json"), ο πυρήνας επιλύει το όνομα με βάση τον τρέχοντα κατάλογο εργασίας της διεργασίας. Τίποτα από τη θέση του ίδιου του σεναρίου δεν συμμετέχει σε αυτή την αναζήτηση. OpenVPN ξεκινά άγκιστρα από κατάλογο που επιλέγει το ίδιο, και η επιλογή cd μπορεί να τον αλλάξει, οπότε ένα σενάριο που δοκιμάστηκε με το χέρι από τον δικό του φάκελο συμπεριφέρεται διαφορετικά μόλις το εκτελέσει ο δαίμονας. Η χειροκίνητη δοκιμή περνά, η εκτέλεση της υπηρεσίας αποτυγχάνει, και η γραμμή καταγραφής αναφέρει μόνο το όνομα που λείπει.

Η Python εκθέτει τη θέση του σεναρίου ως __file__, και αυτό ακριβώς καθιστά δυνατή την αγκύρωση. Path(__file__).resolve().parent / "policy.json" χτίζει μια διαδρομή από το αρχείο και όχι από τη διεργασία. Αυτή η μία γραμμή αφαιρεί την εξάρτηση από τον κατάλογο εργασίας χωρίς να αλλάξει τίποτα στα προνόμια.

Αγκυρώστε τη διαδρομή σκόπιμα και μετά ελέγξτε τι κάνει το resolve

resolve() ακολουθεί συμβολικούς δεσμούς, οπότε μια εγκατάσταση που συνδέει το άγκιστρο στη θέση του αγκυρώνει στον στόχο του δεσμού, όχι στον κατάλογο που κρατά τον δεσμό. Αυτό είναι συνήθως το επιθυμητό για μια ανάπτυξη με εκδόσεις, και είναι λάθος για μια διάταξη που περιμένει δεδομένα δίπλα στον συμβολικό δεσμό. Αποφασίστε τι εννοεί η ανάπτυξη και γράψτε τον κώδικα να ταιριάζει αντί να ανακαλύψετε τη διαφορά στην παραγωγή. Path(__file__).parent χωρίς resolve() διατηρεί τον δικό του κατάλογο του δεσμού.

Αν τα δεδομένα ανήκουν στο στιγμιότυπο και όχι στο πρόγραμμα, πάρτε απόλυτη διαδρομή από τη διαμόρφωση. Η σκληρή κωδικοποίηση μιας θέσης συνδέει το άγκιστρο με μία διάταξη κεντρικού υπολογιστή.

Περάστε τέσσερα όρια με τη σειρά

Ξεκινήστε από τον κατάλογο εργασίας: συγκρίνετε το WorkingDirectory, την επιλογή cd του OpenVPN και οποιοδήποτε περιτύλιγμα αλλάζει κατάλογο πριν από το exec. Στη συνέχεια επιβεβαιώστε την επιλυμένη θέση, γιατί ένα αρχείο με παρόμοιο όνομα σε άλλη ανάπτυξη μπορεί να απαντήσει στην αναζήτηση και να κρύψει το λάθος. Έπειτα έρχεται η όψη του συστήματος αρχείων: ένα chroot ή ένας χώρος ονομάτων προσάρτησης της υπηρεσίας μπορεί να κάνουν μια απόλυτη διαδρομή κεντρικού υπολογιστή απλώς απόν. Τελευταία είναι η ταυτότητα πρόσβασης, που είναι ζήτημα ξεχωριστό από την ορατότητα.

ProtectHome και PrivateTmp κρύβουν διαφορετικές θέσεις, και κανένα από τα δύο δεν εμφανίζεται σε λίστα καταλόγου που λαμβάνεται από τον κεντρικό υπολογιστή. Μια διαδρομή που υπάρχει για το root σε ένα κέλυφος μπορεί να είναι αόρατη μέσα στον χώρο ονομάτων της μονάδας, και γι' αυτό η δοκιμή της ίδιας εντολής έξω από την υπηρεσία αποδεικνύει τόσο λίγα.

Διορθώστε την αναζήτηση χωρίς να διευρύνετε την υπηρεσία

Η αγκύρωση της διαδρομής λύνει μόνο το πρώτο όριο. Δεν αποκαλύπτει κατάλογο που κρύβει η υπηρεσία, και δεν δίνει σε μη προνομιούχο λογαριασμό πρόσβαση σε αρχείο μόνο για το root. Η αύξηση του script-security αλλάζει ποια σενάρια θα εκτελέσει το OpenVPN· δεν έχει καμία επίδραση στο πού επιλύεται ένα σχετικό όνομα. Η αλλαγή του καταλόγου εργασίας για ολόκληρη την υπηρεσία είναι ευρύτερη από το πρόβλημα, γιατί κάθε άλλη σχετική διαδρομή πιστοποιητικού, αρχείου καταγραφής ή βοηθήματος μετακινείται μαζί της.

Προτιμήστε τη στενή διόρθωση: μια ντετερμινιστική διαδρομή στο σενάριο, μια ρητή τιμή διαμόρφωσης για τα δεδομένα του στιγμιότυπου και ιδιοκτησία αρχείων που ταιριάζει με τον λογαριασμό με τον οποίο εκτελείται πραγματικά το άγκιστρο.

Καταγράψτε αποδείξεις που ονομάζουν το όριο

Μια χρήσιμη αναφορά αποτυχίας περιέχει τρία πράγματα: την ακριβή διαδρομή που προσπάθησε το άγκιστρο, το περιβάλλον που την παρήγαγε και ποιο όριο αρνήθηκε. Εκτυπώστε την επιλυμένη διαδρομή και την εξαίρεση χωρίς να χύσετε το περιεχόμενο του αρχείου. Αυτή η τριάδα χωρίζει μια λάθος αγκύρωση από μια κρυφή προσάρτηση και από μια άρνηση δικαιωμάτων, που είναι τρεις διαφορετικές διορθώσεις.

Ο ισχυρισμός ότι το root μπορεί να διαβάσει το αρχείο από ένα τερματικό απαντά σε μία από αυτές τις ερωτήσεις και σε καμία από τις άλλες. Δοκιμάστε αντί αυτού από το ίδιο το πλαίσιο της υπηρεσίας.

Σχετικά άρθρα