RAND_bytes() failed είναι μια δήλωση για μία τοπική πρωτογενή λειτουργία, όχι για τον λογαριασμό, το προκοινοποιημένο κλειδί ή την απομακρυσμένη θύρα. Δύο πολύ διαφορετικές βλάβες παράγουν την ίδια γραμμή και αφήνουν διαφορετικά ίχνη. Η μία είναι ένα κρυπτογραφικό backend που αρνείται να εκπέμψει byte· η άλλη είναι μια διεργασία που δεν φτάνει στην πηγή εντροπίας για την οποία χτίστηκε ο κώδικάς της. Ο διαχωρισμός τους απαιτεί μία ανάγνωση της ουράς σφαλμάτων και μία ματιά στην όψη του συστήματος αρχείων της φυλακισμένης διεργασίας, και αυτός ο έλεγχος ανήκει πριν δημιουργηθεί οτιδήποτε κάτω από το /dev.

Τι ξεχωρίζει η τιμή επιστροφής

Το τεκμηριωμένο συμβόλαιο ξεχωρίζει τρία αποτελέσματα, όχι δύο: 1 για επιτυχία, -1 όταν η φορτωμένη μέθοδος RAND δεν υποστηρίζει το αίτημα, και 0 για άλλες βλάβες, με την εξήγηση να μένει στην ουρά σφαλμάτων. Η αναφορά του RAND_bytes προσθέτει ένα σημείο εύκολο να παραβλεφθεί: η προεπιλεγμένη γεννήτρια παίρνει σπόρο από το λειτουργικό σύστημα σε υποστηριζόμενες πλατφόρμες, και όταν αυτή η σπορά αποτύχει μένει σε κατάσταση σφάλματος αντί να επιστρέψει προβλέψιμα byte.

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

Πότε ένας κρυμμένος κόμβος συσκευής είναι η πραγματική αιτία

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

Δεν χρειάζεται κάθε τυχαία διεπαφή διαδρομή, ωστόσο. Η κλήση συστήματος getrandom του Linux δεν δέχεται ούτε όνομα αρχείου ούτε περιγραφέα αρχείου, και η σελίδα του εγχειριδίου της σημειώνει ότι αυτή η ιδιότητα είναι χρήσιμη ακριβώς εκεί όπου ένα chroot κρύβει διαδρομές συσκευών.

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

Διαβάστε την ουρά σφαλμάτων και μετά την όψη της διεργασίας

Ο ταχύτερος τρόπος να λυθεί το ζήτημα είναι να διαβάσετε τι έχει ήδη καταγράψει η βιβλιοθήκη και μετά να κοιτάξετε απευθείας την όψη μέσα στη φυλακή. Ξεκινήστε με τη δομή OpenSSL που φόρτωσε πραγματικά η υπηρεσία, γιατί οι στοίβες παρόχων διαφέρουν μεταξύ κύριων εκδόσεων και μεταξύ διανομών. Έπειτα ρωτήστε το systemd ποια διεργασία τρέχει και ποιοι περιορισμοί ισχύουν γι' αυτήν. Μόνο όταν και τα δύο γεγονότα είναι στο τραπέζι αξίζει να απαριθμήσετε τους κόμβους που βλέπει αυτή η διεργασία.

openssl version -a
systemctl show openvpn-server@lab -p MainPID -p PrivateDevices -p DevicePolicy
pid=$(systemctl show -p MainPID --value openvpn-server@lab)
sudo ls -l /proc/"$pid"/root/dev/urandom /proc/"$pid"/root/dev/random

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

Προσθέστε την εξάρτηση μόνο όταν μπορείτε να την ονομάσετε

Όταν τα στοιχεία ονομάζουν πράγματι μια διαδρομή, η επιδιόρθωση είναι μικρή: κάντε αυτή τη μία διαδρομή διαθέσιμη μέσα στη φυλακή και αφήστε όλα τα άλλα ήσυχα. Μια bind προσάρτηση του μεμονωμένου κόμβου συνήθως αρκεί, και το mknod με τους τυπικούς αριθμούς major και minor του κόμβου δίνει το ίδιο αποτέλεσμα σε εγκαταστάσεις όπου η προσάρτηση δεν είναι επιλογή. Η διεύρυνση του sandbox, η παροχή πρόσβασης σε κάθε συσκευή χαρακτήρων ή η απενεργοποίηση του PrivateDevices ανταλλάσσει μια στοχευμένη διόρθωση με μια μόνιμη οπισθοδρόμηση ασφαλείας.

Ένας δαίμονας εντροπίας δεν υποκαθιστά αυτή τη διόρθωση. Πακέτα όπως το haveged αλλάζουν πώς τροφοδοτείται η δεξαμενή του πυρήνα· δεν μπορούν να δημιουργήσουν μια διαδρομή που επιτρέπεται να ανοίξει μια φυλακισμένη διεργασία. Η εγκατάσταση ενός μπορεί να κάνει ένα γράφημα υγείας να φαίνεται καλύτερο ενώ η κλήση ανοίγματος εξακολουθεί να αποτυγχάνει. Κρατήστε τα δύο προβλήματα χωριστά, αλλιώς η επόμενη αποτυχία θα αποδοθεί ξανά στο λάθος επίπεδο.

Επαληθεύστε τη γεννήτρια και τη σήραγγα χωριστά

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

sudo systemctl restart openvpn-server@lab
sudo journalctl -u openvpn-server@lab --since -5min --no-pager | grep -iE 'rand|entropy|Initialization Sequence'

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

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