Η υπηρεσία VPN αποτυγχάνει στο EXEC: συγκρίνετε unit, δυαδικό αρχείο και sudoers
Η αποτυχία στο βήμα EXEC σημαίνει ότι το systemd δεν μπόρεσε να ξεκινήσει το δυαδικό αρχείο. Συγκρίνετε τη διαδρομή στο unit, την εγκατεστημένη διαδρομή και την άδεια sudoers πριν αλλάξετε οτιδήποτε.
Χθες η σήραγγα λειτουργούσε, και σήμερα το πρωί το unit είναι νεκρό με Failed at step EXEC spawning /usr/local/bin/vpnclient στο journal. Τα διαπιστευτήρια, οι διαδρομές και ο λογαριασμός δεν μπαίνουν ποτέ σε αυτή την πρόταση. Το systemd μετέτρεψε το ExecStart σε διαδρομή, ζήτησε από τον πυρήνα να την εκτελέσει, και ο πυρήνας αρνήθηκε, συνήθως επειδή δεν υπάρχει τίποτα σε αυτή τη διαδρομή ή επειδή το αρχείο δεν είναι εκτελέσιμο. Αντιμετωπίστε τη βλάβη ως πρόβλημα αρχείου και argv μέχρι η αναλυμένη εντολή να αποδείξει το αντίθετο.
Γιατί το EXEC αποτυγχάνει πριν ξεκινήσει η ταυτοποίηση
Το systemd δεν εκτελεί το ExecStart μέσω shell. Κάνει fork, χτίζει ένα διάνυσμα ορισμάτων από τη γραμμή και καλεί execve στο πρώτο στοιχείο. Αν αυτή η κλήση αποτύχει, η υπηρεσία δεν φτάνει ποτέ στον δικό της κώδικα του πελάτη VPN, οπότε καμία επεξεργασία προφίλ ή έλεγχος διαπιστευτηρίων δεν βοηθά.
Ο κωδικός κατάστασης χωρίζει αυτή την οικογένεια από τις συνηθισμένες καταρρεύσεις. Ένα unit που τερματίζει με status=203/EXEC δεν ξεκίνησε ποτέ διεργασία· ένα unit που ξεκινά και μετά τερματίζει με status=1 μπορεί να απέτυχε στην ταυτοποίηση, στο DNS ή στη δρομολόγηση. Διαβάστε τον κωδικό πριν από το αρχείο καταγραφής του πελάτη, γιατί στην πρώτη περίπτωση το αρχείο καταγραφής του πελάτη θα είναι κενό.
Η διαδρομή στο journal είναι αυτή που χρησιμοποίησε το systemd, όχι απαραίτητα αυτή που επεξεργαστήκατε. Τα drop-in και η έξοδος της γεννήτριας μπορούν να υπερισχύσουν του αρχείου του προμηθευτή, και ένα παρωχημένο daemon-reload αφήνει την παλιά γραμμή στη μνήμη. Γι’ αυτό η πρώτη διάγνωση είναι να ρωτήσετε το systemd τι θεωρεί εντολή, αντί να ανοίξετε το αρχείο που θυμάστε ότι αλλάξατε.
Τρία σημεία όπου γράφεται η διαδρομή του δυαδικού αρχείου
Ένας πελάτης VPN που εγκαταστάθηκε από πακέτο διανομής, σενάριο προμηθευτή και tarball έκδοσης μπορεί να καταλήξει σε τρία διαφορετικά προθέματα. Το unit, ο κανόνας προνομίων και ο εγκαταστάτης κατέγραψαν ο καθένας ένα από αυτά τα προθέματα, και η βλάβη εμφανίζεται όταν δύο από τα τρία δεν συμφωνούν.
| Record | Common value | How to read it |
|---|---|---|
| Unit or drop-in | /usr/local/bin/vpnclient | systemctl cat vpnclient.service |
| Installed binary | /usr/bin/vpnclient | command -v vpnclient, then ls -l the result |
| Sudoers grant | /opt/vpnclient/bin/vpnclient | sudo grep -r vpnclient /etc/sudoers.d/ |
Μια συγκεκριμένη ασυμφωνία φαίνεται έτσι: το σενάριο του προμηθευτή εγκαθιστά στο /usr/local/bin, το tarball αποσυμπιέστηκε κάτω από το /opt, και το unit εξακολουθεί να αναφέρει την παλιά διαδρομή /usr/bin από προηγούμενο πακέτο. Μόνο ένα από αυτά τα αρχεία υπάρχει, και σπάνια είναι αυτό στο ExecStart.
Αποφασίστε ποια διαδρομή είναι κανονική πριν αλλάξετε οποιοδήποτε από τα δύο αρχεία. Αν το πακέτο διανομής κατέχει το δυαδικό αρχείο, η διαδρομή του πακέτου είναι κανονική και το unit πρέπει να την ακολουθήσει. Αν το κατέχει το σενάριο του προμηθευτή, ο ίδιος κανόνας ισχύει για το πρόθεμα του προμηθευτή. Η αντιγραφή ενός δυαδικού αρχείου μεταξύ προθεμάτων δημιουργεί δύο αντίγραφα που αποκλίνουν στην επόμενη αναβάθμιση.
Όταν μια εντολή σε εισαγωγικά γίνεται όνομα αρχείου
Ένας δεύτερος τρόπος αποτυχίας κρύβεται πίσω από την ίδια γραμμή του journal. Κάποιος γράφει αυτό στο unit και περιμένει ο πελάτης να συνδεθεί κατά την εκκίνηση:
ExecStart=/usr/bin/"vpnclient connect office"Το systemd χωρίζει την τιμή σε λέξεις, οπότε η πρώτη λέξη γίνεται /usr/bin/vpnclient connect office, με τα εισαγωγικά να αφαιρούνται ως σύνταξη ομαδοποίησης. Έπειτα ο πυρήνας αναζητά αρχείο του οποίου το όνομα περιέχει κενά, και τέτοιο δεν υπάρχει. Το σφάλμα είναι ίδιο με εκείνο ενός απόντος δυαδικού αρχείου, παρόλο που το αρχείο είναι εγκατεστημένο.
Η υποστηριζόμενη μορφή είναι ένα πραγματικό εκτελέσιμο αρχείο ακολουθούμενο από χωριστά ορίσματα, για παράδειγμα ExecStart=/usr/bin/vpnclient connect office. Αν η ροή εργασίας χρειάζεται πραγματικά αγωγό ή αλυσίδα, βάλτε την σε ένα σενάριο και καλέστε το σενάριο, γιατί το ExecStart δεν έχει &&, ούτε αγωγούς, ούτε επέκταση glob.
Διορθώστε το unit, όχι το σύστημα αρχείων
Η δελεαστική επισκευή είναι ένας συμβολικός σύνδεσμος από την αναμενόμενη διαδρομή προς το πραγματικό δυαδικό αρχείο. Λειτουργεί μέχρι το πακέτο να ενημερωθεί και ο σύνδεσμος να δείχνει σε αρχείο που αφαιρέθηκε, ή μέχρι μια ετικέτα SELinux να μην ταιριάζει πλέον με τον στόχο. Προτιμήστε να επεξεργαστείτε το unit μέσω drop-in, ώστε το αρχείο του προμηθευτή να μείνει ανέγγιχτο και οι αναβαθμίσεις να παραμείνουν προβλέψιμες.
Ο κανόνας προνομίων πρέπει να ταιριάζει με την ίδια διαδρομή και τις ίδιες υποεντολές. Μια καταχώριση sudoers για το /usr/local/bin/vpnclient δεν εξουσιοδοτεί το /usr/bin/vpnclient, και μια καταχώριση που επιτρέπει κάθε όρισμα αφήνει οποιαδήποτε τοπική διεργασία να αναδιαμορφώσει ή να σταματήσει τη σήραγγα. Δώστε τα δύο ρήματα που χρειάζεται το unit και κρατήστε την αποσυναρμολόγηση έξω από αυτό, αν η διακοπή της υπηρεσίας κλείνει ήδη τη διεπαφή.
Εδώ η σύγκριση ανταποδίδει: το unit, η βάση δεδομένων πακέτων και το sudoers πρέπει να ονομάζουν μία διαδρομή. Όταν το κάνουν, το σφάλμα EXEC εξαφανίζεται χωρίς επανεκκίνηση και χωρίς αντίγραφο του δυαδικού αρχείου σε τρίτη θέση.
Αποδείξτε την αναλυμένη εντολή πριν την επανεκκίνηση
sudo systemctl daemon-reload
sudo systemctl cat vpnclient.service
systemctl show -p ExecStart vpnclient.service
systemd-analyze verify /etc/systemd/system/vpnclient.service
sudo systemctl restart vpnclient.service
systemctl status vpnclient.service --no-pagersystemctl show είναι η αποφασιστική έξοδος, γιατί εκτυπώνει το argv που πραγματικά ανέλυσε το systemd, μαζί με οποιοδήποτε drop-in. Το systemd-analyze verify πιάνει μια απούσα ή μη εκτελέσιμη διαδρομή πριν κάνετε επανεκκίνηση, και η εντολή κατάστασης μετά την επανεκκίνηση σας λέει αν η διεργασία υπάρχει τώρα.
Αν το unit ξεκινήσει και μετά αποτύχει, έχετε φύγει από την οικογένεια EXEC και έχετε μπει στη δική του διαχείριση σφαλμάτων του πελάτη. Ελέγξτε το journal για το μήνυμα του πελάτη, όχι για άλλη μια αποτυχία execve. Κρατήστε το diff του unit και το diff του sudoers μαζί στο αρχείο αλλαγών, ώστε η επόμενη αναβάθμιση να μην επαναφέρει σιωπηρά τη διχασμένη διαδρομή.