Ο Theo de Raadt πρότεινε την ενσωμάτωση ενός νέου μηχανισμού στο OpenBSD για τη μείωση της επιφάνειας επίθεσης, ο οποίος υλοποιείται με την επέκταση της κλήσης συστήματος openat. Έχουν προετοιμαστεί ενημερώσεις κώδικα (patches) που εφαρμόζουν πρόσθετες σημαίες για το openat και το open, περιορίζοντας τη δυνατότητα πλοήγησης σε ανώτερους καταλόγους μέσω του "/." και πρόσβασης σε απόλυτες διαδρομές, για τον πυρήνα, το libc και ορισμένες εφαρμογές στο βασικό σύστημα. Οι αλλαγές δεν έχουν ακόμη ενσωματωθεί στο OpenBSD-current και βρίσκονται υπό συζήτηση μεταξύ των προγραμματιστών.
Η οικογένεια κλήσεων συστήματος openat(2) συμπεριφέρεται όπως η open(2), εκτός από το ότι εάν η παράμετρος "path" είναι σχετική, το αρχείο που θα ανοιχτεί είναι σχετικό με τον κατάλογο που σχετίζεται με την περιγραφή αρχείου "fd" και όχι με τον τρέχοντα κατάλογο εργασίας. Εάν δώσετε μια απόλυτη διαδρομή προς την openat, για παράδειγμα: int dirfd = open("/tmp", O_RDONLY | O_DIRECTORY); int hfd = openat(dirfd, "/etc/hosts", O_RDONLY);
Η συνάρτηση openat() θα αγνοήσει το "dirfd" και ως αποτέλεσμα η απόλυτη διαδρομή θα υποβληθεί σε κανονική επεξεργασία.
Επομένως, η αντικατάσταση της open() με openat() δεν βελτιώνει από μόνη της την ασφάλεια του προγράμματος. Αυτή η κλήση μπορεί να επιταχύνει την ανάλυση μονοπατιών, αλλά δεν περιορίζει την πρόσβαση στο σύστημα αρχείων. Σημαίες που απαγορεύουν απόλυτες διαδρομές (για παράδειγμα, RESOLVE_BENEATH και/ή RESOLVE_IN_ROOT για openat2 στο Linux): ο προγραμματιστής πρέπει να τα προσθέσει σε όλες τις κατάλληλες κλήσεις και, όταν αναλαμβάνει τον έλεγχο της διαδικασίας, ο εισβολέας μπορεί να χρησιμοποιήσει άλλους τρόπους για να ανοίξει αρχεία.
Ενώ εργαζόταν στο βοηθητικό πρόγραμμα openrsync, ο Theo χρειάστηκε να περιορίσει τις δυνατότητες διέλευσης του συστήματος αρχείων, αλλά αυτό δεν ήταν δυνατό χρησιμοποιώντας τις συναρτήσεις unveil() και pledge(). Στη συνέχεια, συνέλαβε έναν μηχανισμό παρόμοιο με το openat(), αλλά με χαρακτηριστικά ασφαλείας που θα συμπληρώνουν το pledge/unveil ή ακόμα και θα λειτουργούν απουσία τους.
Η βασική ιδέα είναι να γίνουν οι περιορισμοί μέρος του ίδιου του περιγραφέα καταλόγου. Για να το πετύχουμε αυτό, προτείνουμε τη σημαία F_BELOW, η οποία μπορεί να οριστεί μέσω του fcntl(), ή τη σημαία O_BELOW για το open(). Ένας περιγραφέας "dirfd" που περιορίζεται με αυτόν τον τρόπο θα επιτρέπει μόνο καθοδικές διαβάσεις στο δέντρο καταλόγων: οι κλήσεις openat() με απόλυτη διαδρομή ή οι ανοδικές διαβάσεις μέσω ".." θα αποτύχουν με το σφάλμα ENOENT. Σε περίπτωση επίθεσης εκτέλεσης κώδικα, ο πίνακας περιγραφέα αρχείων της διεργασίας θα περιέχει λιγότερα λειτουργικά "dirfd", περιορίζοντας την επιφάνεια επίθεσης.
Πηγή: opennet.ru
