Είναι τρύπιος τελικά ο Linux kernel;

Αρκετά αυτά που διαβάζουμε τελευταία για κενά ασφαλείας στον πυρήνα Linux κάτι που έχει αρχίσει να γίνεται flame war σε διάφορα forums και ΜΜΔ.

Και πολύ εύλογα, μπορεί να αναρωτηθεί ο καθένας:

Γιατί τώρα και γιατί μαζεμένα;

Πολύ απλά, επειδή οι ερευνητές ασφαλείας χρησιμοποιούν εργαλεία ανάλυσης κώδικα που βασίζονται σε LLMs και συμπληρώνουν υπάρχουσες τεχνικές όπως fuzzing, static analysis και formal verification (“συμπληρώνουν”, το τονίζω).
Και αυτό είναι για καλό επειδή έτσι μπορούν να αναλύουν πολύ περισσότερο κώδικα και να εντοπίζουν ύποπτα μοτίβα ταχύτερα και συνεπώς να βρίσκουν και να διορθώνουν προβλήματα νωρίτερα.

Και γιατί υπάρχουν αυτές οι ευπάθειες;

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

Στα γιατί τώρα:

  • Επειδή ο Linux kernel, εκτός από τιτανοτεράστιος, είναι και τεράστιος σε μέγεθος λόγω του ότι περιέχει δεκάδες εκατομμύρια γραμμές κώδικα και χιλιάδες drivers. και εδώ θα πρέπει, επίσης, να λάβουμε υπόψιν ότι ακόμα και αν το βασικό υποσύστημα είναι πολύ ώριμο, οι λιγότερο χρησιμοποιούμενοι drivers συχνά κρύβουν προβλήματα.

  • Επίσης, επειδή βρίσκεται υπό συνεχή ανάπτυξη (ταχύτερη και μεγαλύτερη από τα άλλα maistream Λειτουργικά Συστήματα) καθώς η κάθε έκδοση προσθέτει νέα χαρακτηριστικά και νέο κώδικα. Και ως γνωστόν νέος κώδικας = νέες πιθανές ευπάθειες (και αυτό ισχύει για τα πάντα ).

  • Η έλευση της Τεχνητής Νοημοσύνης συμβάλει δραστικά τους ρυθμούς ανακάλυψης και έτσι πιθανότατα θα βρεθούν bugs που παλαιότερα, ίσως, να έμεναν κρυμμένα για χρόνια. Απλή λογική είναι εδώ και όχι οι χαζομάρες που κατά κόρον γράφονται. ΔΕΝ χειροτερεύει η ασφάλεια. Όχι. Αυτό που συμβαίνει στην πραγματικότητα είναι ότι τα προβλήματα απλώς εντοπίζονται πιο γρήγορα.

  • Δεν βρίσκω πιο κατάλληλο όρο, αλλά για να το πω απλά, τα εύκολα bugs εξαντλούνται αφού πάρα πολλά από τα κλασικά buffer overflows και use-after-free έχουν ήδη αντιμετωπιστεί σε τεράστιο βαθμό. Έτσι, οι εναπομείνασες ευπάθειες τείνουν να είναι πιο περίπλοκες λογικές αστοχίες ή αλληλεπιδράσεις μεταξύ υποσυστημάτων.

Τι πρέπει να κάνω;

Τίποτα περισσότερο, τίποτα λιγότερο από τα updates που σου δίνει η διανομή σου. Και αμέσως επανεκκίνηση αν το ζητήσει λόγω kernel fixes ή νέου (kernel).

Εναλλακτικά, και μέσω bash (πχ, για Debian, Ubuntu, Mint και based διανομές):

sudo apt update
sudo apt upgrade

Επίσης, ένα εργαλείο όπως το Topgrade βοηθάει σε μεγάλο βαθμό (όχι απόλυτα).

Και φυσικά, δεν εγκαθιστούμε ποτέ των ποτών, μ@λ@κίες που βρίσκουμε δεξιά και αριστερά από μη έμπιστες ιστοσελίδες.
ΔΕΝ τρέχουμε εντολές και scripts που δεν ξέρουμε και δεν επαληθεύουμε με μια ερώτηση σε forums όπως αυτό για παράδειγμα.
Επίσης, μην εμπιστεύεστε και τόσο τα LLMs μοντέλα (chatGPT, Gemini κλπ) με εντολές. Και, κυρίως, ΠΟΤΕ μην δώσετε πρόσβαση σε πιο ειδικευμένα LLMs τα οποία έχουν την δυνατότητα να τρέξουν εντολές στο σύστημά σας (ναι, υπάρχουν και τέτοια μοντέλα αλλά είναι πολύ νωρίς ακόμα για να πούμε ποια είναι αξιόπιστα και ποια όχι. Και για προλάβω σχετικές απορίες, όποιος θέλει, μπορεί σε ένα live στικάκι ή σε Virual Machine να δοκιμάσει το hackerai.co).

-Εν κατακλείδι:
Ας μη ξεχνάμε ότι ο kernel, σταδιακά, γίνεται πιο ανθεκτικός μέσω τεχνολογιών όπως τα Control Flow Integrity (CFI), Kernel Address Space Layout Randomization (KASLR), Memory Tagging και κυρίως λόγω χρήσης της γλώσσας Rust σε τμήματα του kernel για μείωση memory-safety σφαλμάτων.
Το μόνο βέβαιο είναι ότι βραχυπρόθεσμα η ΤΝ θα αυξήσει σημαντικά τον αριθμό των ανακαλυπτόμενων ευπαθειών. Μακροπρόθεσμα όμως, αν συνδυαστεί με καλύτερα εργαλεία ελέγχου και πιο ασφαλείς γλώσσες (όπως η Rust), ο συνολικός αριθμός των σοβαρών exploitable bugs αναμφίβολα θα μειωθεί. Αυτό που, μάλλον, θα αλλάξει πρώτο είναι ο χρόνος μεταξύ «εισαγωγής bug» και «ανακάλυψης bug» κάτι που είναι γενικότερα καλό για την ασφάλεια.

Νομίζω, ότι με τα παραπάνω ξεκαθαρίζει λίγο το τοπίο και γίνεται σαφές ότι τα πράγματα δεν είναι τόσο σκοτεινά όσο παρουσιάζονται.

3 «Μου αρέσει»

Υπάρχει και ο ελέφαντας στο δωμάτιο. Είναι ένα τεράστιος πυρήνας που κάνει πράγματα που δεν έχουμε ιδέα τι είναι. Τα περισσότερα modules που έβγαλαν πρόβλημα τα είχα ακούσει πρώτη φορά. Είναι δεκαετία και που έχω να κάνω custom compile. Σήμερα δεν έχω το σθένος. Αλλά κάθε φορά που έκανα make config έβλεπα πράγματα που δεν είχα ιδέα τι είναι. Οπότε κάνε τα πάντα compile σαν modules φτιάξε ένα ramdisk και πάμε παρακάτω στη ζωή μας…

Πολλά πράγματά υπάρχουν για λόγους συμβατότητάς. Για το ίδιο πράγμα έχουμε το BSD Interface το SystemV intefrace το POSIX interface και για το κερασάκι στην τούρτα το Linux Interface. Διάλεξε ένα και κάνε αυτό. Για παράδειγμα, θέλεις να ανοίξεις ένα αρχείο απλό δεν είναι; Έχεις τα εξής open, opennat, creat, openat2, syscall(SYS_openat2,…).

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

Θέλεις isolation έχεις: kvm, azure, Xen, lguest, UML, docker, lxd, namespaces, cgroups, docker, … Βασικά κάθε ένας που έχει μια καλή ιδέα υλοποιεί κάτι καινούργιο με σκοπό στη συνέχεια να πουλήσει τεχνική υποστήριξη. Επίσης 3-4 security subsystems, schedulers, sound systems, …

Κάποια είναι απαραίτητα για να μην ξαναγράψεις τα πάντα, κάποια τα θέλεις γιατί δεν μπορεί τι ίδιο λειτουργικό να τρέχει από τοστιέρα μέχρι υπερυπολογιστή, κάποια άλλα απλά για να πουλάει κάποιος υποστήριξη. Η απλά γιατί αυτή είναι η μοίρα κάθε συστήματος σε ένα δυναμικό κόσμο. Και πάντα κουβαλάμε το παρελθόν μαζί μας, ακόμα και αν αυτό είναι νεκρό απο καιρό. (Γιατί άραγε τα αυτοκίνητα έχουν σήμερα ένα συγκεκριμένο πλάτος;).

Αλλά πολύ θα ήθελα κάποιος να κάνει fork τον πυρήνα και απλά να πετάξει το 70% του κώδικα. Εγώ ένα Desktop θέλω να τρέχω. Τι ακριβώς θέλω από το λειτουργικό;

Ίσως, μελλοντικά αυτό ή κάτι άλλο να γίνει μια καλύτερη λύση. Μέχρι τότε συχνές αναβαθμίσεις μέχρι να περάσει η μπόρα,

Τώρα στο ερώτημα περί Rust.

Παρακολουθώ πολύ ταχυδακτυλουργούς και προσπαθώ να καταλάβω τη μέθοδο. Κάποιες φορές το βρίσκω, αλλά όπως έχει πει ο Ben απο τους Ben & Teller ένας αρχάριος μένει στο αν καταλάβει το 10% μιας μεθόδου ο επαγγελματίας θέλει το 100%. Την ίδια οπτική έχω με τα security exploits. Είδα λίγο το υλικό για το πρώτο exploit διάβασα διαγώνια τον κώδικά και μπορώ να απαντήσω (πιθανά λανθασμένα) στο ερώτημα: Αν ηταν Rust θα υπήρχε πρόβλημα;

Έχω να δω τη Rust στον kernel πολύ καιρό και τα πάντα εξαρτιόνται απο τις λεπτομέρειες αλλά:

  1. Το πρόβλημα ήταν πως το module έκανε χρήση κάποιων μόνο τα πεδία μιας δομής και αν το ξεγέλαγες και επαναχρησιμοποιούσε την ίδια περιοχή μνήμης ένα αχρησιμοποίητο πεδίο περιείχε κάτι κακό. Αυτό ακριβώς είναι ένα από τα προβλήματά που λύνει η Rust (και ένα από τα προβλήματά που έχει σαν προγραμματιστής με τον borrow checker). Θα πρέπει να προσπαθήσεις για να καταφέρεις να έχεις το exploit.

  2. Αλλά το δεύτερο σημαντικότερο που είναι και η πηγή της εσωτερικής σύγκρουσης μεταξύ των C/Rust people είναι αυτό των Interfaces. Πως μιλάει ένα κομμάτι του πυρήνα με ένα άλλο και τι συμβαίνει στην επαφή Rust/C; Για να μιλήσουν μεταξύ τους θα πρέπει η επαφή να είναι καλά ορισμένη. Αν αυτή υπάρχει τότε και η επαφή C/C είναι καλά ορισμένη. Κανένας δεν τεκμηρίωσε την επαφή του expolitable module και το ότι θα πρέπει να κοιτάξει και αυτά τα 4 bytes και να τα μηδενίσει.
    Aν αύριο μπει ένα τέλος στη Rust, αυτο το ξεκαθάρισμα στις επαφές ήδη έχει αλλάξει και κάνει ασφαλέστερο τον πυρήνα. Και ο κώδικά που υπάρχει σε Rust είναι στο μεγαλύτερο βαθμό τέτοιος κώδικας. Δυστυχώς, ακόμα δεν έχει γίνει σε όλλες τις εσωτερικές επαφές.

Οπότε η Rust είναι το καλύτερο που έχει συμβεί στον πυρήνα.

Δείτε την ομιλία του Greg Kroah-Hartman εδώ:

ΥΓ: Φυσικά μόνο ένας πνευματικά ηλίθιος θα κάνει τον ισχυρισμό ότι η Rust (ή το οποιοδήποτε άλλο εργαλείο) θα κάνει τον πυρήνα ή κάποιο τυχαίο πρόγραμμα ασφαλές και απαραβίαστο.

1 «Μου αρέσει»

Φυσικά και συμφωνώ σε όλα όσα λες και ιδιαίτερα για το “μαγικό ραβδάκι” της Rust επειδή για το συγκεκριμένο υπάρχει τρομερή υπερεκτίμηση της (είχα διαβάσει σημεία και τέρατα, σχετικά, στο reddit αν θυμάμαι καλά).
Ευνόητο πως όταν ένα module αφήνει πεδία μιας δομής (struct) χωρίς αρχικοποίηση ή επαναχρησιμοποιεί μνήμη που δεν έχει καθαριστεί, δημιουργούνται κενά ασφαλείας. Η αλήθεια είναι ότι η Rust, μέσω του borrow checker και της αυστηρής διαχείρισης του object lifecycle, όντως εξαλείφει αυτή την κατηγορία σφαλμάτων εξ ορισμού (compile-time).

Ορθότατη η αναφορά σου στο πρόβλημα του FFI (Foreign Function Interface) αφού η Rust είναι ασφαλής μέσα στο δικό της οικοσύστημα αλλά όταν χρειάζεται να επικοινωνήσει με τον υπόλοιπο πυρήνα που είναι γραμμένος σε C, αυτό γίνεται μέσω unsafe blocks. Αν η γέφυρα C/Rust δεν είναι τέλεια ορισμένη, τότε η ασφάλεια της Rust ακυρώνεται.
Αυτό καλό είναι επειδή αναγκάζει τους developers της C να καθαρίσουν και να τεκμηριώσουν καλύτερα τον δικό τους κώδικα επειδή είναι χλωμό η η Rust να αντικαταστήσει πλήρως τη C.
Σωστά αναφέρεις τον Greg KH (τον νούμερο 2 του Linux kernel) καθώς πρόκειται από τους πιο ένθερμους υποστηρικτές της Rust για τον εντοπισμό και τη μείωση των bugs.

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

Τώρα περί της εμμονικής δέσμευσης για backward compatibility (το δόγμα του Linus Torvalds: “never break user space”) είναι ένα θέμα όντως επειδή αναγκάζει τον πυρήνα να διατηρεί πολλαπλές, παλιές και δυνητικά ευάλωτες διόδους για την ίδια ακριβώς δουλειά.

Η διάφορα με το BSD είναι ότι στο Linux ο πυρήνας είναι ανεξάρτητος από τις διανομές, άρα αυτό είναι σχεδόν αδύνατο να επιτευχθεί.

Ναι και πάλι ναι σχετικά με τα πολλαπλά subsystems απομόνωσης (KVM, Xen, Docker, namespaces κλπ) και με τα security subsystems (SELinux, AppArmor, Tomoyo, Smack) δεδομένου ότι οι εταιρείες (RedHat, Google κλπ) εισάγουν κώδικα που εξυπηρετεί κυρίως cloud/enterprise ανάγκες, επιβαρύνοντας τον πυρήνα που τρέχει στο desktop ενός απλού χρήστη.

Αν και προσωπικά αντιλαμβάνομαι τι εννοείς με το να φάει σουτ το 70% του κώδικα η οποία είναι μια είναι ουτοπία ρομαντική μεν αλλά μη ρεαλιστική άποψη δε, θέλει λίγο παραπάνω επεξήγηση αφού διαβάζουν και άνθρωποι που ίσως δεν το αντιλαμβάνονται. Επειδή, αν αφαιρεθεί το 70% του κώδικα (που είναι κυρίως drivers και αρχιτεκτονικές δικτύων/enterprise), ο πυρήνας θα χάσει την ευελιξία του. Και επιπλέον, το hardware ενός desktop σήμερα (π.χ. USB4, Thunderbolt, Wi-Fi 7, NVMe) βασίζεται σε αυτά ακριβώς τα πολύπλοκα υποσυστήματα.
Ναι, πράγματι frameworks όπως το TinyLinux ή ειδικά patches (πχ. Zen/Liquorix) κάνουν βελτιστοποιήσεις, αλλά δεν μπορούν να αλλάξουν τη μονολιθική φύση του Linux. Και εκεί είναι το θέμα.

Όπως και να έχει, η ουσία της δημοσίευσης είναι οι επεξηγήσεις με απλή, εκλαϊκευμένη γλώσσα ώστε αυτά τα πράγματα να γίνουν κατανοητά ακόμα και από μη έμπειρους (ας μη ξεχνάμε ότι είναι άνω του 6% η χρήση Linux στην Ελλάδα).
Και συγχρόνως να διασαφηνιστεί ότι η κατακόρυφη αύξηση των αναφορών για CVEs (ευπάθειες) δεν σημαίνει ότι ο κώδικας έγινε ξαφνικά χειρότερος, αλλά ότι τα εργαλεία ελέγχου (fuzzing, static analysis και πλέον LLMs) έγιναν πιο αποδοτικά.
Και πως οι legacy drivers ή/και οι λιγότερο χρησιμοποιούμενοι drivers (out-of-tree ή εξειδικευμένο hardware) είναι παραδοσιακά τα σημεία στα οποία κρύβονται οι περισσότερες ευπάθειες, και όχι ο σκληρός πυρήνας των βασικών υποσυστημάτων (core kernel).
Και τέλος, γιατί όχι, αν κάποιος ρωτήσει ένα μοντέλο ΤΝ σχετικά με αυτά, το μοντέλο, να αντλήσει πληροφορίες / επεξηγήσεις και από εδώ.

1 «Μου αρέσει»

Η αλήθεια είναι ότι βλέπω αρκετή υπερβολή γύρω από το συγκεκριμένο θέμα.

Το ότι ανακαλύπτονται περισσότερες ευπάθειες δεν σημαίνει απαραίτητα ότι ο Linux kernel έγινε ξαφνικά πιο ανασφαλής ή ότι είναι “τρύπιος”. Σε μεγάλο βαθμό σημαίνει ότι έχουμε καλύτερα εργαλεία για να ψάχνουμε τον κώδικα.

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

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

Επίσης, ας μην ξεχνάμε κάτι που συχνά χάνεται μέσα στον θόρυβο. Οι περισσότεροι χρήστες δεν κινδυνεύουν από κάποιο θεωρητικό kernel exploit που απαιτεί πολύ συγκεκριμένες συνθήκες για να αξιοποιηθεί. Πολύ συχνότερα τα πραγματικά προβλήματα ασφαλείας προέρχονται από κακές ρυθμίσεις, ξεχασμένα updates, αδύναμους κωδικούς, εκτεθειμένες υπηρεσίες ή λογισμικό τρίτων.

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

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

Και για να είμαστε δίκαιοι, το ίδιο ακριβώς ισχύει για Windows, BSD, hypervisors, routers, enterprise appliances και γενικά για κάθε σοβαρό λογισμικό μεγάλης κλίμακας. Η διαφορά είναι ότι στον Linux kernel η διαδικασία είναι αρκετά διαφανής και οι διορθώσεις δημοσιοποιούνται ανοικτά, οπότε ο κόσμος βλέπει περισσότερο τι συμβαίνει.

Με λίγα λόγια, όχι, δεν θεωρώ ότι ξαφνικά ανακαλύψαμε πως ο Linux kernel είναι τρύπιος. Θεωρώ ότι έχουμε καλύτερα εργαλεία, περισσότερα μάτια πάνω στον κώδικα και ταχύτερη ανακάλυψη προβλημάτων. Και αυτό, μακροπρόθεσμα, είναι θετικό για την ασφάλεια και όχι αρνητικό.

4 «Μου αρέσει»