O
d wersji jądra 5.14 został wprowadzony zestaw poprawek dający systemowi Linux opcjonalną blokadę jądra mającą na celu wzmocnienie granicy między prawami administracyjnymi, a jądrem. Po jej włączeniu różne elementy funkcjonalności jądra (w tym nisko poziomowy dostęp do sprzętu) są ograniczone dla różnych programów. Większość głównych dystrybucji Linuksa zawiera już zestaw tych poprawek pod postacią zaczepu (ang. hook) do Linux Security Modules (LSM), czyli programowalnego szkieletu do implementacji polityk bezpieczeństwa (ang. security policies) i obowiązkowej kontroli dostępu (ang. Mandatory Access Control) w jądrze systemu. Lockdown LSM zapewnia prostą implementację poziomu blokady jądra dzięki wiersza poleceń jądra lub pseudo systemowi plików sysfs. Listę aktywnych modułów bezpieczeństwa w LSM można znaleźć odczytując plik: /sys/kernel/security/lsm. Jest to lista rozdzielona przecinkami, odzwierciedlająca kolejność, w jakiej przeprowadzane są sprawdzenia modułów.
Nas interesuje moduł lockdown. Wszystkie oficjalnie wspierane jądra inicjalizują ten moduł LSM, ale w standardowej konfiguracji żadne z nich nie wymusza żadnego poziomu trybu blokady. Może on być ustawiony w trzech stanach (kontrolowanych przez specjalny plik: /sys/kernel/security/lockdown):
root@darkstar:~# cat /sys/kernel/security/lockdown [none] integrity confidentialityTryb none to stan, w którym nic nie jest wymuszone, a moduł pozostaje wyłączony. Gdy lockdown jest w stanie integralności (ang. integrity) jądro próbuje zapobiec każdej operacji, która może naruszyć jego integralność. Na przykład: ładowanie niepodpisanych modułów lub wykonywanie niepodpisanego kodu dzięki kexec nie będzie już możliwe. Inne blokady i ograniczenia obejmują specjalne pliki urządzeń i usługi jądra, które umożliwiają bezpośredni dostęp do jego obrazu np. /dev/(k)mem; hibernowanie systemu w niezaszyfrowanej formie; użycie debugfs itd. (o reszcie przeczytamy na stronie podręcznika LSM).
root@darkstar:~# insmod rootkit.ko insmod: ERROR: could not insert module rootkit.ko: Operation not permitted root@darkstar:~# dmesg [118711.437971] Lockdown: insmod: unsigned module loading is restricted; see man kernel_lockdown.7Ostatnim trybem jest poufny (ang. confidentiality) – jest on najbardziej restrykcyjny, w którym mechanizm lockdown będzie również próbował zapobiec wyciekom informacji z jądra, w tym: użyciu BPF do odczytu pamięci RAM, kprobes, perf, tracefs i dostępu do /proc/kcore. Konkretny tryb możemy włączyć przy pomocy przekazania odpowiedniego parametru jądra (lockdown=) przy starcie systemu Linux lub już podczas jego działania poprzez sysfs. Warto jednak pamiętać, iż możemy wprowadzać system w stan tylko bardziej restrykcyjny, ale nie z powrotem. To znaczy, iż gdy jesteśmy w trybie integralności, możemy przełączyć się tylko w tryb poufności, ale już nie wyłączymy trybu blokady:
root@darkstar:~# cat /sys/kernel/security/lockdown none [integrity] confidentiality root@darkstar:~# echo none > /sys/kernel/security/lockdown -bash: echo: write error: Operation not permittedJeśli kompilujemy własne wersje jądra możemy też ustawić początkowy stan mechanizmu lockdown w LSM dzięki opcji CONFIG_LOCK_DOWN_KERNEL_FORCE_INTEGRITY=y, aby “fabrycznie” był bardziej restrykcyjny. Który tryb będzie dla nas odpowiedni musimy sprawdzić w praktyce. W zależności od roli i używanego systemu serwera choćby stan integralności może okazać się zbyt restrykcyjny. W dodatku wprowadzenie blokady po uruchomieniu systemu może skutkować innym zachowaniem niż wybranie stanu blokady podczas uruchamiania jądra. Na przykład: jeżeli zależy nam na uruchomieniu procesów, które powinny uzyskać zasoby przed wprowadzeniem blokady – możemy wykorzystać sysfs na odpowiednim etapie uruchamiania serwisów – w przeciwnym wypadku mechanizm lockdown powinien być wyzwalany z parametrów uruchomienia jądra.
Więcej informacji: Kernel lockdown mode, Lockdown LSM